GNU Octave 7.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-2022 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?
61
62// TRUE means print struct array contents, up to the number of levels
63// specified by struct_levels_to_print.
64static bool Vprint_struct_array_contents = false;
65
66void
67octave_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
89Cell
90octave_struct::dotref (const octave_value_list& idx, bool auto_add)
91{
92 Cell retval;
93
94 assert (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
111static void
113{
114 error ("invalid index for structure array assignment");
115}
116
117static void
118err_invalid_index_type (const std::string& nm, char t)
119{
120 error ("%s cannot be indexed with %c", nm.c_str (), t);
121}
122
123static void
124maybe_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
140octave_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:
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
206octave_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:
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
298octave_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 assert (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 assert (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:
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 assert (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 assert (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:
554 }
555
556 retval.maybe_mutate ();
557
558 return retval;
559}
560
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
573std::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
592void
593octave_struct::print (std::ostream& os, bool)
594{
595 print_raw (os);
596}
597
598void
599octave_struct::print_raw (std::ostream& os, bool) const
600{
602
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
656bool
657octave_struct::print_name_tag (std::ostream& os, const std::string& name) const
658{
659 bool retval = false;
660
661 indent (os);
662
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
678static bool
679scalar (const dim_vector& dims)
680{
681 return dims.ndims () == 2 && dims(0) == 1 && dims(1) == 1;
682}
683
684std::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
712bool
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
748bool
750{
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") : Cell (t2));
799
800 m.setfield (nm, tcell);
801 }
802
803 if (! is)
804 error ("load: failed to load structure");
805
806 m_map = m;
807 }
808 else if (len == 0)
809 m_map = octave_map (dv);
810 else
812
813 return success;
814}
815
816bool
817octave_struct::save_binary (std::ostream& os, bool save_as_floats)
818{
819 octave_map m = map_value ();
820
821 octave_idx_type nf = m.nfields ();
822
823 dim_vector dv = dims ();
824 if (dv.ndims () < 1)
825 return false;
826
827 // Use negative value for ndims
828 int32_t di = - dv.ndims ();
829 os.write (reinterpret_cast<char *> (&di), 4);
830 for (int i = 0; i < dv.ndims (); i++)
831 {
832 di = dv(i);
833 os.write (reinterpret_cast<char *> (&di), 4);
834 }
835
836 int32_t len = nf;
837 os.write (reinterpret_cast<char *> (&len), 4);
838
839 // Iterating over the list of keys will preserve the order of the
840 // fields.
841 string_vector keys = m.fieldnames ();
842
843 for (octave_idx_type i = 0; i < nf; i++)
844 {
845 std::string key = keys(i);
846
847 octave_value val = m_map.contents (key);
848
849 bool b = save_binary_data (os, val, key, "", 0, save_as_floats);
850
851 if (! b)
852 return ! os.fail ();
853 }
854
855 return true;
856}
857
858bool
859octave_struct::load_binary (std::istream& is, bool swap,
861{
862 bool success = true;
863 int32_t len;
864 if (! is.read (reinterpret_cast<char *> (&len), 4))
865 return false;
866 if (swap)
868
869 dim_vector dv (1, 1);
870
871 if (len < 0)
872 {
873 // We have explicit dimensions.
874 int mdims = -len;
875
876 int32_t di;
877 dv.resize (mdims);
878
879 for (int i = 0; i < mdims; i++)
880 {
881 if (! is.read (reinterpret_cast<char *> (&di), 4))
882 return false;
883 if (swap)
884 swap_bytes<4> (&di);
885 dv(i) = di;
886 }
887
888 if (! is.read (reinterpret_cast<char *> (&len), 4))
889 return false;
890 if (swap)
892 }
893
894 if (len > 0)
895 {
896 octave_map m (dv);
897
898 for (octave_idx_type j = 0; j < len; j++)
899 {
900 octave_value t2;
901 bool dummy;
902 std::string doc;
903
904 // recurse to read cell elements
905 std::string nm = read_binary_data (is, swap, fmt, "",
906 dummy, t2, doc);
907
908 if (! is)
909 break;
910
911 Cell tcell = (t2.iscell () ? t2.xcell_value ("load: internal error loading struct elements") : Cell (t2));
912
913 m.setfield (nm, tcell);
914 }
915
916 if (! is)
917 error ("load: failed to load structure");
918
919 m_map = m;
920 }
921 else if (len == 0)
922 m_map = octave_map (dv);
923 else
924 success = false;
925
926 return success;
927}
928
929bool
931 bool save_as_floats)
932{
933#if defined (HAVE_HDF5)
934
935 hid_t data_hid = -1;
936
937#if defined (HAVE_HDF5_18)
938 data_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT,
940#else
941 data_hid = H5Gcreate (loc_id, name, 0);
942#endif
943 if (data_hid < 0) return false;
944
945 // recursively add each element of the structure to this group
946 octave_map m = map_value ();
947
948 octave_idx_type nf = m.nfields ();
949
950 // Iterating over the list of keys will preserve the order of the
951 // fields.
952 string_vector keys = m.fieldnames ();
953
954 for (octave_idx_type i = 0; i < nf; i++)
955 {
956 std::string key = keys(i);
957
958 octave_value val = m_map.contents (key);
959
960 bool retval2 = add_hdf5_data (data_hid, val, key, "", false,
961 save_as_floats);
962
963 if (! retval2)
964 break;
965 }
966
967 H5Gclose (data_hid);
968
969 return true;
970
971#else
972 octave_unused_parameter (loc_id);
973 octave_unused_parameter (name);
974 octave_unused_parameter (save_as_floats);
975
976 warn_save ("hdf5");
977
978 return false;
979#endif
980}
981
982bool
984{
985 bool retval = false;
986
987#if defined (HAVE_HDF5)
988
990
991 herr_t retval2 = 0;
992 octave_map m (dim_vector (1, 1));
993 int current_item = 0;
994 hsize_t num_obj = 0;
995#if defined (HAVE_HDF5_18)
996 hid_t group_id = H5Gopen (loc_id, name, octave_H5P_DEFAULT);
997#else
998 hid_t group_id = H5Gopen (loc_id, name);
999#endif
1000 H5Gget_num_objs (group_id, &num_obj);
1001 H5Gclose (group_id);
1002
1003 // FIXME: fields appear to be sorted alphabetically on loading.
1004 // Why is that happening?
1005
1006 while (current_item < static_cast<int> (num_obj)
1007 && (retval2 = hdf5_h5g_iterate (loc_id, name, &current_item,
1008 &dsub)) > 0)
1009 {
1010 octave_value t2 = dsub.tc;
1011
1012 Cell tcell = (t2.iscell () ? t2.xcell_value ("load: internal error loading struct elements") : Cell (t2));
1013
1014 m.setfield (dsub.name, tcell);
1015
1016 }
1017
1018 if (retval2 >= 0)
1019 {
1020 m_map = m;
1021 retval = true;
1022 }
1023
1024#else
1025 octave_unused_parameter (loc_id);
1026 octave_unused_parameter (name);
1027
1028 warn_load ("hdf5");
1029#endif
1030
1031 return retval;
1032}
1033
1034mxArray *
1035octave_struct::as_mxArray (bool interleaved) const
1036{
1037 int nf = nfields ();
1038 string_vector kv = map_keys ();
1039
1040 OCTAVE_LOCAL_BUFFER (const char *, f, nf);
1041
1042 for (int i = 0; i < nf; i++)
1043 f[i] = kv[i].c_str ();
1044
1045 mxArray *retval = new mxArray (interleaved, dims (), nf, f);
1046
1047 mxArray **elts = static_cast<mxArray **> (retval->get_data ());
1048
1049 mwSize nel = numel ();
1050
1051 mwSize ntot = nf * nel;
1052
1053 for (int i = 0; i < nf; i++)
1054 {
1055 Cell c = m_map.contents (kv[i]);
1056
1057 const octave_value *p = c.data ();
1058
1059 mwIndex k = 0;
1060 for (mwIndex j = i; j < ntot; j += nf)
1061 elts[j] = new mxArray (interleaved, p[k++]);
1062 }
1063
1064 return retval;
1065}
1066
1069{
1070 if (n < m_map.numel ())
1071 return m_map.checkelem (n);
1072 else
1073 return octave_value ();
1074}
1075
1076bool
1078 const octave_value& x)
1079{
1080 bool retval = false;
1081
1082 if (n < m_map.numel ())
1083 {
1084 // To avoid copying the scalar struct, it just stores a pointer to
1085 // itself.
1086 const octave_scalar_map *sm_ptr;
1087 void *here = reinterpret_cast<void *>(&sm_ptr);
1088 return (x.get_rep ().fast_elem_insert_self (here, btyp_struct)
1089 && m_map.fast_elem_insert (n, *sm_ptr));
1090 }
1091
1092 return retval;
1093}
1094
1096 "struct");
1097
1098void
1099octave_scalar_struct::break_closure_cycles (const std::shared_ptr<octave::stack_frame>& frame)
1100{
1101 for (octave_idx_type i = 0; i < m_map.nfields (); i++)
1103}
1104
1107{
1108 octave_value retval;
1109
1110 assert (idx.length () == 1);
1111
1112 std::string nm = idx(0).string_value ();
1113
1114 maybe_warn_invalid_field_name (nm, "subsref");
1115
1116 retval = m_map.getfield (nm);
1117
1118 if (! auto_add && retval.is_undefined ())
1119 error_with_id ("Octave:invalid-indexing",
1120 "structure has no member '%s'", nm.c_str ());
1121
1122 return retval;
1123}
1124
1126octave_scalar_struct::subsref (const std::string& type,
1127 const std::list<octave_value_list>& idx)
1128{
1129 octave_value retval;
1130
1131 if (type[0] == '.')
1132 {
1133 int skip = 1;
1134
1135 retval = dotref (idx.front ());
1136
1137 if (idx.size () > 1)
1138 retval = retval.next_subsref (type, idx, skip);
1139 }
1140 else
1141 retval = to_array ().subsref (type, idx);
1142
1143 return retval;
1144}
1145
1147octave_scalar_struct::subsref (const std::string& type,
1148 const std::list<octave_value_list>& idx,
1149 int nargout)
1150{
1151 octave_value_list retval;
1152
1153 if (type[0] == '.')
1154 {
1155 int skip = 1;
1156
1157 retval(0) = dotref (idx.front ());
1158
1159 if (idx.size () > 1)
1160 retval = retval(0).next_subsref (nargout, type, idx, skip);
1161 }
1162 else
1163 retval = to_array ().subsref (type, idx, nargout);
1164
1165 return retval;
1166}
1167
1169octave_scalar_struct::subsref (const std::string& type,
1170 const std::list<octave_value_list>& idx,
1171 bool auto_add)
1172{
1173 octave_value retval;
1174
1175 if (type[0] == '.')
1176 {
1177 int skip = 1;
1178
1179 retval = dotref (idx.front (), auto_add);
1180
1181 if (idx.size () > 1)
1182 retval = retval.next_subsref (auto_add, type, idx, skip);
1183 }
1184 else
1185 retval = to_array ().subsref (type, idx, auto_add);
1186
1187 return retval;
1188}
1189
1190/*
1191%!test
1192%! x(1).a.a = 1;
1193%! x(2).a.a = 2;
1194%! assert (size (x), [1, 2]);
1195%! assert (x(1).a.a, 1);
1196%! assert (x(2).a.a, 2);
1197*/
1198
1201 const std::string& type)
1202{
1203 octave_value retval;
1204
1205 if (type.length () > 0 && type[0] == '.' && ! val.isstruct ())
1206 retval = octave_map ();
1207 else
1208 retval = val;
1209
1210 return retval;
1211}
1212
1214octave_scalar_struct::subsasgn (const std::string& type,
1215 const std::list<octave_value_list>& idx,
1216 const octave_value& rhs)
1217{
1218 octave_value retval;
1219
1220 if (idx.front ().empty ())
1221 error ("missing index in indexed assignment");
1222
1223 if (type[0] == '.')
1224 {
1225 int n = type.length ();
1226
1227 octave_value t_rhs = rhs;
1228
1229 octave_value_list key_idx = idx.front ();
1230
1231 assert (key_idx.length () == 1);
1232
1233 std::string key = key_idx(0).string_value ();
1234
1235 maybe_warn_invalid_field_name (key, "subsasgn");
1236
1237 if (n > 1)
1238 {
1239 std::list<octave_value_list> next_idx (idx);
1240
1241 next_idx.erase (next_idx.begin ());
1242
1243 std::string next_type = type.substr (1);
1244
1245 octave_value tmp;
1246 auto pkey = m_map.seek (key);
1247 if (pkey != m_map.end ())
1248 {
1249 m_map.contents (pkey).make_unique ();
1250 tmp = m_map.contents (pkey);
1251 }
1252
1253 bool orig_undefined = tmp.is_undefined ();
1254
1255 if (orig_undefined || tmp.is_zero_by_zero ())
1256 {
1257 tmp = octave_value::empty_conv (next_type, rhs);
1258 tmp.make_unique (); // probably a no-op.
1259 }
1260 else
1261 // optimization: ignore the copy still stored inside our m_map.
1262 tmp.make_unique (1);
1263
1264 t_rhs = (orig_undefined
1265 ? tmp.undef_subsasgn (next_type, next_idx, rhs)
1266 : tmp.subsasgn (next_type, next_idx, rhs));
1267 }
1268
1269 m_map.setfield (key, t_rhs.storable_value ());
1270
1271 count++;
1272 retval = this;
1273 }
1274 else
1275 {
1276 // Forward this case to octave_struct.
1278 retval = tmp.subsasgn (type, idx, rhs);
1279 }
1280
1281 return retval;
1282}
1283
1286{
1287 // octave_map handles indexing itself.
1288 return octave_map (m_map).index (idx, resize_ok);
1289}
1290
1291std::size_t
1293{
1294 // Neglect the size of the fieldnames.
1295
1296 std::size_t retval = 0;
1297
1298 for (auto p = m_map.cbegin (); p != m_map.cend (); p++)
1299 {
1300 std::string key = m_map.key (p);
1301
1303
1304 retval += val.byte_size ();
1305 }
1306
1307 return retval;
1308}
1309
1310void
1311octave_scalar_struct::print (std::ostream& os, bool)
1312{
1313 print_raw (os);
1314}
1315
1316void
1317octave_scalar_struct::print_raw (std::ostream& os, bool) const
1318{
1320
1321 if (Vstruct_levels_to_print >= 0)
1322 {
1323 bool max_depth_reached = (Vstruct_levels_to_print-- == 0);
1324
1325 bool print_fieldnames_only = max_depth_reached;
1326
1329
1330 string_vector key_list = m_map.fieldnames ();
1331
1332 for (octave_idx_type i = 0; i < key_list.numel (); i++)
1333 {
1334 std::string key = key_list[i];
1335
1336 octave_value val = m_map.contents (key);
1337
1338 if (print_fieldnames_only)
1339 {
1340 indent (os);
1341 os << key;
1342 dim_vector dv = val.dims ();
1343 os << ": " << dv.str () << ' ' << val.type_name ();
1344 newline (os);
1345 }
1346 else
1347 val.print_with_name (os, key);
1348 }
1349
1352 }
1353 else
1354 {
1355 indent (os);
1356 os << "<structure>";
1357 newline (os);
1358 }
1359}
1360
1361bool
1363 const std::string& name) const
1364{
1365 bool retval = false;
1366
1367 indent (os);
1368
1370 os << name << " = ";
1371 else
1372 {
1373 os << name << " =";
1374 newline (os);
1375 if (! Vcompact_format)
1376 newline (os);
1377
1379
1380 indent (os);
1381 os << "scalar structure containing the fields:";
1382 newline (os);
1383 if (! Vcompact_format)
1384 newline (os);
1385
1387
1388 retval = true;
1389 }
1390
1391 return retval;
1392}
1393
1394std::string
1397{
1398 // Scalar struct. Rows are fields, single column for values.
1399
1400 octave_value val = m_map.contents (r);
1401
1402 std::string tname = val.type_name ();
1403 dim_vector dv = val.dims ();
1404 std::string dimstr = dv.str ();
1405 return "[" + dimstr + " " + tname + "]";
1406}
1407
1408bool
1410{
1411 octave_map m = map_value ();
1412
1413 octave_idx_type nf = m.nfields ();
1414
1415 const dim_vector dv = dims ();
1416
1417 os << "# ndims: " << dv.ndims () << "\n";
1418
1419 for (int i = 0; i < dv.ndims (); i++)
1420 os << ' ' << dv(i);
1421 os << "\n";
1422
1423 os << "# length: " << nf << "\n";
1424
1425 // Iterating over the list of keys will preserve the order of the
1426 // fields.
1427 string_vector keys = m.fieldnames ();
1428
1429 for (octave_idx_type i = 0; i < nf; i++)
1430 {
1431 std::string key = keys(i);
1432
1433 octave_value val = m_map.contents (key);
1434
1435 bool b = save_text_data (os, val, key, false, 0);
1436
1437 if (! b)
1438 return ! os.fail ();
1439 }
1440
1441 return true;
1442}
1443
1444bool
1446{
1447 octave_idx_type len = 0;
1448
1449 if (! extract_keyword (is, "length", len) || len < 0)
1450 error ("load: failed to extract number of elements in structure");
1451
1452 if (len > 0)
1453 {
1455
1456 for (octave_idx_type j = 0; j < len; j++)
1457 {
1458 octave_value t2;
1459 bool dummy;
1460
1461 // recurse to read cell elements
1462 std::string nm
1463 = read_text_data (is, "", dummy, t2, j, false);
1464
1465 if (! is)
1466 break;
1467
1468 m.setfield (nm, t2);
1469 }
1470
1471 if (! is)
1472 error ("load: failed to load structure");
1473
1474 m_map = m;
1475 }
1476 else if (len == 0)
1478 else
1480
1481 return true;
1482}
1483
1484bool
1485octave_scalar_struct::save_binary (std::ostream& os, bool save_as_floats)
1486{
1487 octave_map m = map_value ();
1488
1489 octave_idx_type nf = m.nfields ();
1490
1491 int32_t len = nf;
1492 os.write (reinterpret_cast<char *> (&len), 4);
1493
1494 // Iterating over the list of keys will preserve the order of the
1495 // fields.
1496 string_vector keys = m.fieldnames ();
1497
1498 for (octave_idx_type i = 0; i < nf; i++)
1499 {
1500 std::string key = keys(i);
1501
1502 octave_value val = m_map.contents (key);
1503
1504 bool b = save_binary_data (os, val, key, "", 0, save_as_floats);
1505
1506 if (! b)
1507 return ! os.fail ();
1508 }
1509
1510 return true;
1511}
1512
1513bool
1514octave_scalar_struct::load_binary (std::istream& is, bool swap,
1516{
1517 bool success = true;
1518 int32_t len;
1519 if (! is.read (reinterpret_cast<char *> (&len), 4))
1520 return false;
1521 if (swap)
1522 swap_bytes<4> (&len);
1523
1524 if (len > 0)
1525 {
1527
1528 for (octave_idx_type j = 0; j < len; j++)
1529 {
1530 octave_value t2;
1531 bool dummy;
1532 std::string doc;
1533
1534 // recurse to read cell elements
1535 std::string nm = read_binary_data (is, swap, fmt, "",
1536 dummy, t2, doc);
1537
1538 if (! is)
1539 break;
1540
1541 m.setfield (nm, t2);
1542 }
1543
1544 if (! is)
1545 error ("load: failed to load structure");
1546
1547 m_map = m;
1548 }
1549 else if (len == 0)
1551 else
1552 success = false;
1553
1554 return success;
1555}
1556
1557bool
1559 bool save_as_floats)
1560{
1561#if defined (HAVE_HDF5)
1562
1563 hid_t data_hid = -1;
1564
1565#if defined (HAVE_HDF5_18)
1566 data_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT,
1568#else
1569 data_hid = H5Gcreate (loc_id, name, 0);
1570#endif
1571 if (data_hid < 0) return false;
1572
1573 // recursively add each element of the structure to this group
1575
1576 octave_idx_type nf = m.nfields ();
1577
1578 // Iterating over the list of keys will preserve the order of the
1579 // fields.
1580 string_vector keys = m.fieldnames ();
1581
1582 for (octave_idx_type i = 0; i < nf; i++)
1583 {
1584 std::string key = keys(i);
1585
1586 octave_value val = m_map.contents (key);
1587
1588 bool retval2 = add_hdf5_data (data_hid, val, key, "", false,
1589 save_as_floats);
1590
1591 if (! retval2)
1592 break;
1593 }
1594
1595 H5Gclose (data_hid);
1596
1597 return true;
1598
1599#else
1600 octave_unused_parameter (loc_id);
1601 octave_unused_parameter (name);
1602 octave_unused_parameter (save_as_floats);
1603
1604 warn_save ("hdf5");
1605
1606 return false;
1607#endif
1608}
1609
1610bool
1612{
1613 bool retval = false;
1614
1615#if defined (HAVE_HDF5)
1616
1617 hdf5_callback_data dsub;
1618
1619 herr_t retval2 = 0;
1621 int current_item = 0;
1622 hsize_t num_obj = 0;
1623#if defined (HAVE_HDF5_18)
1624 hid_t group_id = H5Gopen (loc_id, name, octave_H5P_DEFAULT);
1625#else
1626 hid_t group_id = H5Gopen (loc_id, name);
1627#endif
1628 H5Gget_num_objs (group_id, &num_obj);
1629 H5Gclose (group_id);
1630
1631 // FIXME: fields appear to be sorted alphabetically on loading.
1632 // Why is that happening?
1633
1634 while (current_item < static_cast<int> (num_obj)
1635 && (retval2 = hdf5_h5g_iterate (loc_id, name, &current_item,
1636 &dsub)) > 0)
1637 {
1638 octave_value t2 = dsub.tc;
1639
1640 m.setfield (dsub.name, t2);
1641
1642 }
1643
1644 if (retval2 >= 0)
1645 {
1646 m_map = m;
1647 retval = true;
1648 }
1649
1650#else
1651 octave_unused_parameter (loc_id);
1652 octave_unused_parameter (name);
1653
1654 warn_load ("hdf5");
1655#endif
1656
1657 return retval;
1658}
1659
1660mxArray *
1661octave_scalar_struct::as_mxArray (bool interleaved) const
1662{
1663 int nf = nfields ();
1664 string_vector kv = map_keys ();
1665
1666 OCTAVE_LOCAL_BUFFER (const char *, f, nf);
1667
1668 for (int i = 0; i < nf; i++)
1669 f[i] = kv[i].c_str ();
1670
1671 mxArray *retval = new mxArray (interleaved, dims (), nf, f);
1672
1673 mxArray **elts = static_cast<mxArray **> (retval->get_data ());
1674
1675 mwSize nel = numel ();
1676
1677 mwSize ntot = nf * nel;
1678
1679 for (int i = 0; i < nf; i++)
1680 {
1681 Cell c = m_map.contents (kv[i]);
1682
1683 const octave_value *p = c.data ();
1684
1685 mwIndex k = 0;
1686 for (mwIndex j = i; j < ntot; j += nf)
1687 elts[j] = new mxArray (interleaved, p[k++]);
1688 }
1689
1690 return retval;
1691}
1692
1695{
1696 return new octave_struct (octave_map (m_map));
1697}
1698
1699bool
1701 builtin_type_t btyp) const
1702{
1703
1704 if (btyp == btyp_struct)
1705 {
1706 *(reinterpret_cast<const octave_scalar_map **>(where)) = &m_map;
1707 return true;
1708 }
1709 else
1710 return false;
1711}
1712
1713OCTAVE_NAMESPACE_BEGIN
1714
1715DEFUN (struct, args, ,
1716 doc: /* -*- texinfo -*-
1717@deftypefn {} {@var{s} =} struct ()
1718@deftypefnx {} {@var{s} =} struct (@var{field1}, @var{value1}, @var{field2}, @var{value2}, @dots{})
1719@deftypefnx {} {@var{s} =} struct (@var{obj})
1720
1721Create a scalar or array structure and initialize its values.
1722
1723The @var{field1}, @var{field2}, @dots{} variables are strings specifying the
1724names of the fields and the @var{value1}, @var{value2}, @dots{} variables
1725can be of any type.
1726
1727If the values are cell arrays, create a structure array and initialize its
1728values. The dimensions of each cell array of values must match. Singleton
1729cells and non-cell values are repeated so that they fill the entire array.
1730If the cells are empty, create an empty structure array with the specified
1731field names.
1732
1733If the argument is an object, return the underlying struct.
1734
1735Observe that the syntax is optimized for struct @strong{arrays}. Consider
1736the following examples:
1737
1738@example
1739@group
1740struct ("foo", 1)
1741 @result{} scalar structure containing the fields:
1742 foo = 1
1743
1744struct ("foo", @{@})
1745 @result{} 0x0 struct array containing the fields:
1746 foo
1747
1748struct ("foo", @{ @{@} @})
1749 @result{} scalar structure containing the fields:
1750 foo = @{@}(0x0)
1751
1752struct ("foo", @{1, 2, 3@})
1753 @result{} 1x3 struct array containing the fields:
1754 foo
1755
1756@end group
1757@end example
1758
1759@noindent
1760The first case is an ordinary scalar struct---one field, one value. The
1761second produces an empty struct array with one field and no values, since
1762being passed an empty cell array of struct array values. When the value is
1763a cell array containing a single entry, this becomes a scalar struct with
1764that single entry as the value of the field. That single entry happens
1765to be an empty cell array.
1766
1767Finally, if the value is a non-scalar cell array, then @code{struct}
1768produces a struct @strong{array}.
1769@seealso{cell2struct, fieldnames, getfield, setfield, rmfield, isfield,
1770orderfields, isstruct, structfun}
1771@end deftypefn */)
1772{
1773 int nargin = args.length ();
1774
1775 // struct ([]) returns an empty struct.
1776
1777 // struct (empty_matrix) returns an empty struct with the same
1778 // dimensions as the empty matrix.
1779
1780 // Note that struct () creates a 1x1 struct with no fields for
1781 // compatibility with Matlab.
1782
1783 if (nargin == 1 && args(0).isstruct ())
1784 return ovl (args(0));
1785
1786 if (nargin == 1 && args(0).isobject ())
1787 return ovl (args(0).map_value ());
1788
1789 if ((nargin == 1 || nargin == 2)
1790 && args(0).isempty () && args(0).is_real_matrix ())
1791 {
1792 if (nargin == 2)
1793 {
1794 Array<std::string> cstr = args(1).xcellstr_value ("struct: second argument should be a cell array of field names");
1795
1796 return ovl (octave_map (args(0).dims (), cstr));
1797 }
1798 else
1799 return ovl (octave_map (args(0).dims ()));
1800 }
1801
1802 // Check for "field", VALUE pairs.
1803
1804 for (int i = 0; i < nargin; i += 2)
1805 {
1806 if (! args(i).is_string () || i + 1 >= nargin)
1807 error (R"(struct: additional arguments must occur as "field", VALUE pairs)");
1808 }
1809
1810 // Check that the dimensions of the values correspond.
1811
1812 dim_vector dims (1, 1);
1813
1814 int first_dimensioned_value = 0;
1815
1816 for (int i = 1; i < nargin; i += 2)
1817 {
1818 if (args(i).iscell ())
1819 {
1820 dim_vector argdims (args(i).dims ());
1821
1822 if (! scalar (argdims))
1823 {
1824 if (! first_dimensioned_value)
1825 {
1826 dims = argdims;
1827 first_dimensioned_value = i + 1;
1828 }
1829 else if (dims != argdims)
1830 {
1831 error ("struct: dimensions of parameter %d "
1832 "do not match those of parameter %d",
1833 first_dimensioned_value, i+1);
1834 }
1835 }
1836 }
1837 }
1838
1839 // Create the return value.
1840
1841 octave_map m_map (dims);
1842
1843 for (int i = 0; i < nargin; i+= 2)
1844 {
1845 // Get key.
1846
1847 std::string key (args(i).string_value ());
1848
1849 maybe_warn_invalid_field_name (key, "struct");
1850
1851 // Value may be v, { v }, or { v1, v2, ... }
1852 // In the first two cases, we need to create a cell array of
1853 // the appropriate dimensions filled with v. In the last case,
1854 // the cell array has already been determined to be of the
1855 // correct dimensions.
1856
1857 if (args(i+1).iscell ())
1858 {
1859 const Cell c (args(i+1).cell_value ());
1860
1861 if (scalar (c.dims ()))
1862 m_map.setfield (key, Cell (dims, c(0)));
1863 else
1864 m_map.setfield (key, c);
1865 }
1866 else
1867 m_map.setfield (key, Cell (dims, args(i+1)));
1868 }
1869
1870 return ovl (m_map);
1871}
1872
1873/*
1874%!shared x
1875%! x(1).a=1; x(2).a=2; x(1).b=3; x(2).b=3;
1876%!assert (struct ("a",1, "b",3), x(1))
1877%!assert (isempty (x([])))
1878%!assert (isempty (struct ("a",{}, "b",{})))
1879%!assert (struct ("a",{1,2}, "b",{3,3}), x)
1880%!assert (struct ("a",{1,2}, "b",3), x)
1881%!assert (struct ("a",{1,2}, "b",{3}), x)
1882%!assert (struct ("b",3, "a",{1,2}), x)
1883%!assert (struct ("b",{3}, "a",{1,2}), x)
1884%!test x = struct ([]);
1885%!assert (size (x), [0,0])
1886%!assert (isstruct (x))
1887%!assert (isempty (fieldnames (x)))
1888%!fail ('struct ("a",{1,2},"b",{1,2,3})', 'dimensions of parameter 2 do not match those of parameter 4')
1889%!error <arguments must occur as "field", VALUE pairs> struct (1,2,3,4)
1890%!fail ('struct ("1",2,"3")', 'struct: additional arguments must occur as "field", VALUE pairs')
1891*/
1892
1893DEFUN (isstruct, args, ,
1894 doc: /* -*- texinfo -*-
1895@deftypefn {} {} isstruct (@var{x})
1896Return true if @var{x} is a structure or a structure array.
1897@seealso{ismatrix, iscell, isa}
1898@end deftypefn */)
1899{
1900 if (args.length () != 1)
1901 print_usage ();
1902
1903 return ovl (args(0).isstruct ());
1904}
1905
1906DEFUN (__fieldnames__, args, ,
1907 doc: /* -*- texinfo -*-
1908@deftypefn {} {} __fieldnames__ (@var{struct})
1909@deftypefnx {} {} __fieldnames__ (@var{obj})
1910Internal function.
1911
1912Implements @code{fieldnames()} for structures and Octave objects.
1913@seealso{fieldnames}
1914@end deftypefn */)
1915{
1916 octave_value retval;
1917
1918 // Input validation has already been done in fieldnames.m.
1919 octave_value arg = args(0);
1920
1921 octave_map m = arg.map_value ();
1922
1923 string_vector keys = m.fieldnames ();
1924
1925 if (keys.isempty ())
1926 retval = Cell (0, 1);
1927 else
1928 retval = Cell (keys);
1929
1930 return retval;
1931}
1932
1933DEFUN (isfield, args, ,
1934 doc: /* -*- texinfo -*-
1935@deftypefn {} {} isfield (@var{x}, "@var{name}")
1936@deftypefnx {} {} isfield (@var{x}, @var{name})
1937Return true if the @var{x} is a structure and it includes an element named
1938@var{name}.
1939
1940If @var{name} is a cell array of strings then a logical array of equal
1941dimension is returned.
1942@seealso{fieldnames}
1943@end deftypefn */)
1944{
1945 if (args.length () != 2)
1946 print_usage ();
1947
1948 octave_value retval = false;
1949
1950 if (args(0).isstruct ())
1951 {
1952 octave_map m = args(0).map_value ();
1953
1954 // FIXME: should this work for all types that can do
1955 // structure reference operations?
1956 if (args(1).is_string ())
1957 {
1958 std::string key = args(1).string_value ();
1959
1960 retval = m.isfield (key);
1961 }
1962 else if (args(1).iscell ())
1963 {
1964 Cell c = args(1).cell_value ();
1965 boolNDArray bm (c.dims ());
1966 octave_idx_type n = bm.numel ();
1967
1968 for (octave_idx_type i = 0; i < n; i++)
1969 {
1970 if (c(i).is_string ())
1971 {
1972 std::string key = c(i).string_value ();
1973
1974 bm(i) = m.isfield (key);
1975 }
1976 else
1977 bm(i) = false;
1978 }
1979
1980 retval = bm;
1981 }
1982 }
1983
1984 return retval;
1985}
1986
1987DEFUN (numfields, args, ,
1988 doc: /* -*- texinfo -*-
1989@deftypefn {} {} numfields (@var{s})
1990Return the number of fields of the structure @var{s}.
1991@seealso{fieldnames}
1992@end deftypefn */)
1993{
1994 if (args.length () != 1)
1995 print_usage ();
1996
1997 if (! args(0).isstruct ())
1998 error ("numfields: argument must be a struct");
1999
2000 return ovl (static_cast<double> (args(0).nfields ()));
2001}
2002
2003/*
2004## test isfield
2005%!test
2006%! x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3;
2007%! assert (isfield (x, "b"));
2008%!assert (isfield (struct ("a", "1"), "a"))
2009%!assert (isfield ({1}, "c"), false)
2010%!assert (isfield (struct ("a", "1"), 10), false)
2011%!assert (isfield (struct ("a", "b"), "a "), false)
2012%!assert (isfield (struct ("a", 1, "b", 2), {"a", "c"}), [true, false])
2013*/
2014
2015OCTAVE_NORETURN
2016static void
2018{
2019 error ("cell2struct: FIELDS must be a cell array of strings or a scalar string");
2020}
2021
2022static Array<std::string>
2024{
2025 if (arg.is_string ())
2026 {
2027 if (arg.rows () != 1)
2029
2030 return Array<std::string> (dim_vector (1, 1), arg.string_value ());
2031 }
2032
2033 if (arg.iscell ())
2034 {
2035 const Cell c = arg.cell_value ();
2036
2037 Array<std::string> retval (c.dims ());
2038
2039 for (octave_idx_type i = 0; i < c.numel (); i++)
2040 {
2041 const octave_value val = c(i);
2042
2043 if (! val.is_string () || val.rows () != 1)
2045
2046 retval(i) = c(i).string_value ();
2047 }
2048
2049 return retval;
2050 }
2051
2053}
2054
2055DEFUN (cell2struct, args, ,
2056 doc: /* -*- texinfo -*-
2057@deftypefn {} {} cell2struct (@var{cell}, @var{fields})
2058@deftypefnx {} {} cell2struct (@var{cell}, @var{fields}, @var{dim})
2059Convert @var{cell} to a structure.
2060
2061The number of fields in @var{fields} must match the number of elements in
2062@var{cell} along dimension @var{dim}, that is
2063@code{numel (@var{fields}) == size (@var{cell}, @var{dim})}. If @var{dim}
2064is omitted, a value of 1 is assumed.
2065
2066@example
2067@group
2068A = cell2struct (@{"Peter", "Hannah", "Robert";
2069 185, 170, 168@},
2070 @{"Name","Height"@}, 1);
2071A(1)
2072 @result{}
2073 @{
2074 Name = Peter
2075 Height = 185
2076 @}
2077
2078@end group
2079@end example
2080@seealso{struct2cell, cell2mat, struct}
2081@end deftypefn */)
2082{
2083 int nargin = args.length ();
2084
2085 if (nargin < 2 || nargin > 3)
2086 print_usage ();
2087
2088 const Cell vals
2089 = args(0).xcell_value ("cell2struct: argument CELL must be of type cell");
2090
2091 const Array<std::string> fields = get_cell2struct_fields (args(1));
2092
2093 int dim = 0;
2094
2095 if (nargin == 3)
2096 {
2097 if (! args(2).is_real_scalar ())
2098 error ("cell2struct: DIM must be a real scalar");
2099
2100 dim = args(2).int_value () - 1;
2101 }
2102
2103 if (dim < 0)
2104 error ("cell2struct: DIM must be a valid dimension");
2105
2106 octave_idx_type ext = (vals.ndims () > dim ? vals.dims ()(dim) : 1);
2107
2108 if (ext != fields.numel ())
2109 error ("cell2struct: number of FIELDS does not match dimension");
2110
2111 int nd = std::max (dim+1, vals.ndims ());
2112 // result dimensions.
2113 dim_vector rdv = vals.dims ().redim (nd);
2114
2115 assert (ext == rdv(dim));
2116 if (nd == 2)
2117 {
2118 rdv(0) = rdv(1-dim);
2119 rdv(1) = 1;
2120 }
2121 else
2122 {
2123 for (int i = dim + 1; i < nd; i++)
2124 rdv(i-1) = rdv(i);
2125
2126 rdv.resize (nd-1);
2127 }
2128
2129 octave_map m_map (rdv);
2131
2132 for (octave_idx_type i = 0; i < ext; i++)
2133 {
2134 ia(dim) = i;
2135 m_map.setfield (fields(i), vals.index (ia).reshape (rdv));
2136 }
2137
2138 return ovl (m_map);
2139}
2140
2141/*
2142## test cell2struct versus struct2cell
2143%!test
2144%! keys = cellstr (char (floor (rand (100,10)*24+65)))';
2145%! vals = mat2cell (rand (100,1), ones (100,1), 1)';
2146%! s = struct ([keys; vals]{:});
2147%! t = cell2struct (vals, keys, 2);
2148%! assert (s, t);
2149%! assert (struct2cell (s), vals');
2150%! assert (fieldnames (s), keys');
2151
2152%!assert (cell2struct ({1; 2}, {"a"; "b"}), struct ("a", 1, "b", 2))
2153
2154%!assert (cell2struct ({}, {"f"}, 3), struct ("f", {}))
2155
2156%!assert (cell2struct ({1; 2; 3; 4}, {'a', 'b'; 'c', 'd'}),
2157%! struct ('a', 1, 'c', 2, 'b', 3, 'd', 4));
2158%!assert (cell2struct ({1, 2, 3, 4}, {'a', 'b'; 'c', 'd'}, 2),
2159%! struct ('a', 1, 'c', 2, 'b', 3, 'd', 4));
2160%!error cell2struct ({1, 2, 3, 4}, {'a', 'b'; 'c', 'd'})
2161*/
2162
2163DEFUN (rmfield, args, ,
2164 doc: /* -*- texinfo -*-
2165@deftypefn {} {@var{sout} =} rmfield (@var{s}, "@var{f}")
2166@deftypefnx {} {@var{sout} =} rmfield (@var{s}, @var{f})
2167Return a @emph{copy} of the structure (array) @var{s} with the field @var{f}
2168removed.
2169
2170If @var{f} is a cell array of strings or a character array, remove each of
2171the named fields.
2172@seealso{orderfields, fieldnames, isfield}
2173@end deftypefn */)
2174{
2175 if (args.length () != 2)
2176 print_usage ();
2177
2178 octave_map m = args(0).xmap_value ("rmfield: first argument must be a struct");
2179
2180 octave_value_list fval = Fcellstr (args(1), 1);
2181
2182 Cell fcell = fval(0).cell_value ();
2183
2184 for (int i = 0; i < fcell.numel (); i++)
2185 {
2186 std::string key = fcell(i).string_value ();
2187
2188 if (! m.isfield (key))
2189 error ("rmfield: structure does not contain field %s", key.c_str ());
2190
2191 m.rmfield (key);
2192 }
2193
2194 return ovl (m);
2195}
2196
2197/*
2198## test rmfield
2199%!shared x
2200%! x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3; x(6).f="abc123";
2201%!
2202%!test
2203%! y = rmfield (x, "c");
2204%! assert (fieldnames (y), {"d"; "a"; "b"; "f"});
2205%! assert (size (y), [1, 6]);
2206%!test
2207%! y = rmfield (x, {"a", "f"});
2208%! assert (fieldnames (y), {"d"; "b"; "c"});
2209%! assert (size (y), [1, 6]);
2210*/
2211
2212DEFUN (struct_levels_to_print, args, nargout,
2213 doc: /* -*- texinfo -*-
2214@deftypefn {} {@var{val} =} struct_levels_to_print ()
2215@deftypefnx {} {@var{old_val} =} struct_levels_to_print (@var{new_val})
2216@deftypefnx {} {} struct_levels_to_print (@var{new_val}, "local")
2217Query or set the internal variable that specifies the number of
2218structure levels to display.
2219
2220When called from inside a function with the @qcode{"local"} option, the
2221variable is changed locally for the function and any subroutines it calls.
2222The original variable value is restored when exiting the function.
2223@seealso{print_struct_array_contents}
2224@end deftypefn */)
2225{
2226 return set_internal_variable (Vstruct_levels_to_print, args, nargout,
2227 "struct_levels_to_print", -1,
2229}
2230
2231DEFUN (print_struct_array_contents, args, nargout,
2232 doc: /* -*- texinfo -*-
2233@deftypefn {} {@var{val} =} print_struct_array_contents ()
2234@deftypefnx {} {@var{old_val} =} print_struct_array_contents (@var{new_val})
2235@deftypefnx {} {} print_struct_array_contents (@var{new_val}, "local")
2236Query or set the internal variable that specifies whether to print struct
2237array contents.
2238
2239If true, values of struct array elements are printed. This variable does
2240not affect scalar structures whose elements are always printed. In both
2241cases, however, printing will be limited to the number of levels specified
2242by @var{struct_levels_to_print}.
2243
2244When called from inside a function with the @qcode{"local"} option, the
2245variable is changed locally for the function and any subroutines it calls.
2246The original variable value is restored when exiting the function.
2247@seealso{struct_levels_to_print}
2248@end deftypefn */)
2249{
2251 "print_struct_array_contents");
2252}
2253
2254OCTAVE_NAMESPACE_END
void swap_bytes< 4 >(void *ptr)
Definition: byte-swap.h:63
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
void make_unique(void)
Definition: Array.h:215
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:411
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:487
const T * data(void) const
Size of the specified dimension.
Definition: Array.h:616
int ndims(void) const
Size of the specified dimension.
Definition: Array.h:627
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
void * get_data(void) const
Definition: mxarray.h:497
static const idx_vector colon
Definition: idx-vector.h:483
octave::refcount< octave_idx_type > count
Definition: ov-base.h:906
void decrement_indent_level(void) const
Definition: ov-base.h:890
void increment_indent_level(void) const
Definition: ov-base.h:887
OCTINTERP_API void indent(std::ostream &os) const
Definition: ov-base.cc:1364
OCTINTERP_API void newline(std::ostream &os) const
Definition: ov-base.cc:1383
OCTINTERP_API void warn_load(const char *type) const
Definition: ov-base.cc:1152
virtual bool is_magic_colon(void) const
Definition: ov-base.h:439
friend class octave_value
Definition: ov-base.h:256
OCTINTERP_API void warn_save(const char *type) const
Definition: ov-base.cc:1161
bool isempty(void) const
Definition: ov-base.h:391
octave_idx_type columns(void) const
Definition: oct-map.h:395
void rmfield(const std::string &key)
Definition: oct-map.cc:298
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
const Cell & contents(const_iterator p) const
Definition: oct-map.h:331
bool isfield(const std::string &name) const
Definition: oct-map.h:347
void delete_elements(const octave::idx_vector &i)
Definition: oct-map.cc:1229
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
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 octave_value & contents(const_iterator p) const
Definition: oct-map.h:205
const_iterator cbegin(void) const
Definition: oct-map.h:195
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:1611
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
Definition: ov-struct.cc:1558
octave_value to_array(void)
Definition: ov-struct.cc:1694
bool print_name_tag(std::ostream &os, const std::string &name) const
Definition: ov-struct.cc:1362
mxArray * as_mxArray(bool interleaved) const
Definition: ov-struct.cc:1661
dim_vector dims(void) const
Definition: ov-struct.h:226
octave_scalar_map scalar_map_value(void) const
Definition: ov-struct.h:255
static octave_value numeric_conv(const octave_value &val, const std::string &type)
Definition: ov-struct.cc:1200
string_vector map_keys(void) const
Definition: ov-struct.h:257
octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov-struct.cc:1285
bool load_ascii(std::istream &is)
Definition: ov-struct.cc:1445
void print(std::ostream &os, bool pr_as_read_syntax=false)
Definition: ov-struct.cc:1311
octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition: ov-struct.cc:1126
octave_map map_value(void) const
Definition: ov-struct.h:253
octave_value dotref(const octave_value_list &idx, bool auto_add=false)
Definition: ov-struct.cc:1106
std::size_t byte_size(void) const
Definition: ov-struct.cc:1292
octave_idx_type nfields(void) const
Definition: ov-struct.h:237
bool save_binary(std::ostream &os, bool save_as_floats)
Definition: ov-struct.cc:1485
bool save_ascii(std::ostream &os)
Definition: ov-struct.cc:1409
bool fast_elem_insert_self(void *where, builtin_type_t btyp) const
Definition: ov-struct.cc:1700
octave_scalar_map m_map
Definition: ov-struct.h:288
void print_raw(std::ostream &os, bool pr_as_read_syntax=false) const
Definition: ov-struct.cc:1317
octave_idx_type numel(void) const
Definition: ov-struct.h:232
bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format fmt)
Definition: ov-struct.cc:1514
void break_closure_cycles(const std::shared_ptr< octave::stack_frame > &frame)
Definition: ov-struct.cc:1099
std::string edit_display(const float_display_format &fmt, octave_idx_type i, octave_idx_type j) const
Definition: ov-struct.cc:1395
octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
Definition: ov-struct.cc:1214
octave_base_value * try_narrowing_conversion(void)
Definition: ov-struct.cc:79
octave_map m_map
Definition: ov-struct.h:166
bool fast_elem_insert(octave_idx_type n, const octave_value &x)
Definition: ov-struct.cc:1077
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:170
mxArray * as_mxArray(bool interleaved) const
Definition: ov-struct.cc:1035
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:983
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:930
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:1068
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:817
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:859
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:1434
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_idx_type length(void) const
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:1449
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
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:1025
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:1070
void error(const char *fmt,...)
Definition: error.cc:980
#define panic_impossible()
Definition: error.h:411
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
QString name
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:1061
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:1407
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:287
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:363
void mxArray
Definition: mex.h:58
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:222
builtin_type_t
Definition: ov-base.h:75
@ btyp_struct
Definition: ov-base.h:90
OCTAVE_EXPORT octave_value_list Fcellstr(const octave_value_list &args, int)
Definition: ov-cell.cc:1315
static bool scalar(const dim_vector &dims)
Definition: ov-struct.cc:679
static Array< std::string > get_cell2struct_fields(const octave_value &arg)
Definition: ov-struct.cc:2023
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:2017
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:115
std::string name
Definition: ls-hdf5.h:109
OCTAVE_NAMESPACE_BEGIN bool valid_identifier(const char *s)
Definition: utils.cc:77
octave_value set_internal_variable(bool &var, const octave_value_list &args, int nargout, const char *nm)
Definition: variables.cc:587
F77_RET_T len
Definition: xerbla.cc:61