GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ov-class.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2007-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 <memory>
32#include <ostream>
33
34#include "Array-util.h"
35#include "byte-swap.h"
36#include "oct-locbuf.h"
37#include "lo-mappers.h"
38
39#include "Cell.h"
40#include "defun.h"
41#include "error.h"
42#include "file-ops.h"
43#include "errwarn.h"
44#include "interpreter-private.h"
45#include "interpreter.h"
46#include "load-path.h"
47#include "ls-hdf5.h"
48#include "ls-oct-text.h"
49#include "ls-oct-binary.h"
50#include "ls-utils.h"
51#include "mxarray.h"
52#include "oct-lvalue.h"
53#include "oct-hdf5.h"
54#include "ov-class.h"
55#include "ov-fcn.h"
56#include "ov-typeinfo.h"
57#include "ov-usr-fcn.h"
58#include "pager.h"
59#include "parse.h"
60#include "pr-output.h"
61#include "unwind-prot.h"
62#include "variables.h"
63
64
65int octave_class::t_id (-1);
66
67const std::string octave_class::t_name ("class");
68
69void
70octave_class::register_type (octave::type_info& ti)
71{
72 t_id = ti.register_type (octave_class::t_name, "<unknown>",
73 octave_value (new octave_class ()));
74}
75
76octave_class::octave_class (const octave_map& m, const std::string& id,
77 const octave_value_list& parents)
78 : octave_base_value (), m_map (m), c_name (id), m_obsolete_copies (0)
79{
80 octave_idx_type n = parents.length ();
81
82 for (octave_idx_type idx = 0; idx < n; idx++)
83 {
84 octave_value parent = parents(idx);
85
86 if (! parent.isobject ())
87 error ("parents must be objects");
88
89 std::string pcnm = parent.class_name ();
90
91 if (find_parent_class (pcnm))
92 error ("duplicate class in parent tree");
93
94 m_parent_list.push_back (pcnm);
95
97 octave_idx_type p_nel = parent.numel ();
98
99 if (nel == 0)
100 {
101 if (p_nel == 0)
102 {
103 // No elements in MAP or the parent class object,
104 // so just add the field name.
105
106 m_map.assign (pcnm, Cell (m_map.dims ()));
107 }
108 else if (p_nel == 1)
109 {
110 if (m_map.nfields () == 0)
111 {
112 // No elements or fields in MAP, but the
113 // parent is class object with one element.
114 // Resize to match size of parent class and
115 // make the parent a field in MAP.
116
117 m_map.resize (parent.dims ());
118
119 m_map.assign (pcnm, parent);
120 }
121 else
122 {
123 // No elements in MAP, but we have at least
124 // one field. So don't resize, just add the
125 // field name.
126
127 m_map.assign (pcnm, Cell (m_map.dims ()));
128 }
129 }
130 else if (m_map.nfields () == 0)
131 {
132 // No elements or fields in MAP and more than one
133 // element in the parent class object, so we can
134 // resize MAP to match parent dimsenions, then
135 // distribute the elements of the parent object to
136 // the elements of MAP.
137
138 dim_vector parent_dims = parent.dims ();
139
140 m_map.resize (parent_dims);
141
142 Cell c (parent_dims);
143
144 octave_map pmap = parent.map_value ();
145
146 std::list<std::string> plist
147 = parent.parent_class_name_list ();
148
149 for (octave_idx_type i = 0; i < p_nel; i++)
150 c(i) = octave_value (pmap.index (i), pcnm, plist);
151
152 m_map.assign (pcnm, c);
153 }
154 else
155 error ("class: parent class dimension mismatch");
156 }
157 else if (nel == 1 && p_nel == 1)
158 {
159 // Simple assignment.
160
161 m_map.assign (pcnm, parent);
162 }
163 else
164 {
165 if (p_nel == 1)
166 {
167 // Broadcast the scalar parent class object to
168 // each element of MAP.
169
170 Cell pcell (m_map.dims (), parent);
171
172 m_map.assign (pcnm, pcell);
173 }
174 else if (nel == p_nel)
175 {
176 // FIXME: is there a better way to do this?
177
178 // The parent class object has the same number of
179 // elements as the map we are using to create the
180 // new object, so distribute those elements to
181 // each element of the new object by first
182 // splitting the elements of the parent class
183 // object into a cell array with one element per
184 // cell. Then do the assignment all at once.
185
186 Cell c (parent.dims ());
187
188 octave_map pmap = parent.map_value ();
189
190 std::list<std::string> plist
191 = parent.parent_class_name_list ();
192
193 for (octave_idx_type i = 0; i < p_nel; i++)
194 c(i) = octave_value (pmap.index (i), pcnm, plist);
195
196 m_map.assign (pcnm, c);
197 }
198 else
199 error ("class: parent class dimension mismatch");
200 }
201 }
202
203 octave::symbol_table& symtab = octave::__get_symbol_table__ ("octave_class");
204
205 symtab.add_to_parent_map (id, m_parent_list);
206}
207
210{
212 {
213 // All remaining copies are obsolete. We don't actually need to clone.
214 count++;
215 return this;
216 }
217 else
218 {
219 // In theory, this shouldn't be happening, but it's here just in case.
222
223 return clone ();
224 }
225}
226
227std::string
229{
230 std::string retval = class_name ();
231
232 if (nparents () > 0)
233 {
234 octave::tree_evaluator& tw
235 = octave::__get_evaluator__ ("octave_class::get_current_method_class");
236
237 octave_function *fcn = tw.current_function ();
238
239 // Here we are just looking to see if FCN is a method or constructor
240 // for any class, not specifically this one.
241 if (fcn && (fcn->is_class_method () || fcn->is_class_constructor ()))
242 retval = fcn->dispatch_class ();
243 }
244
245 return retval;
246}
247
248OCTAVE_NORETURN static
249void
251{
252 error ("invalid index for class");
253}
254
255OCTAVE_NORETURN static
256void
258{
259 error ("invalid index for class assignment");
260}
261
262OCTAVE_NORETURN static
263void
264err_invalid_index_type (const std::string& nm, char t)
265{
266 error ("%s cannot be indexed with %c", nm.c_str (), t);
267}
268
269void
270octave_class::break_closure_cycles (const std::shared_ptr<octave::stack_frame>& frame)
271{
272 for (octave_idx_type j = 0; j < m_map.nfields (); j++)
273 {
274 Cell& c = m_map.contents (j);
275
276 for (octave_idx_type i = 0; i < c.numel (); i++)
277 c(i).break_closure_cycles (frame);
278 }
279}
280
281Cell
283{
284 assert (idx.length () == 1);
285
286 std::string method_class = get_current_method_class ();
287
288 // Find the class in which this method resides before attempting to access
289 // the requested field.
290
291 octave_base_value *obvp = find_parent_class (method_class);
292
293 if (obvp == nullptr)
294 error ("malformed class");
295
296 octave_map my_map = (obvp != this) ? obvp->map_value () : m_map;
297
298 std::string nm = idx(0).xstring_value ("invalid index for class");
299
300 octave_map::const_iterator p = my_map.seek (nm);
301
302 if (p == my_map.end ())
303 error ("class has no member '%s'", nm.c_str ());
304
305 return my_map.contents (p);
306}
307
308Matrix
310{
312 return octave_base_value::size ();
313
314 Matrix retval (1, 2, 1.0);
315
316 octave::symbol_table& symtab
317 = octave::__get_symbol_table__ ("octave_class::size");
318
319 octave_value meth = symtab.find_method ("size", class_name ());
320
321 if (meth.is_defined ())
322 {
323 count++;
324 octave_value_list args (1, octave_value (this));
325
326 octave_value_list lv = octave::feval (meth.function_value (), args, 1);
327 if (lv.length () <= 0
328 || ! lv(0).is_matrix_type () || ! lv(0).dims ().isvector ())
329 error ("@%s/size: invalid return value", class_name ().c_str ());
330
331 retval = lv(0).matrix_value ();
332 }
333 else
334 {
335 dim_vector dv = dims ();
336
337 int nd = dv.ndims ();
338
339 retval.resize (1, nd);
340
341 for (int i = 0; i < nd; i++)
342 retval(i) = dv(i);
343 }
344
345 return retval;
346}
347
350{
352 return octave_base_value::xnumel (idx);
353
354 octave_idx_type retval = -1;
355 const std::string cn = class_name ();
356
357 octave::symbol_table& symtab
358 = octave::__get_symbol_table__ ("octave_class::numel");
359
360 octave_value meth = symtab.find_method ("numel", cn);
361
362 if (meth.is_defined ())
363 {
364 octave_value_list args (idx.length () + 1, octave_value ());
365
366 count++;
367 args(0) = octave_value (this);
368
369 for (octave_idx_type i = 0; i < idx.length (); i++)
370 args(i+1) = idx(i);
371
372 octave_value_list lv = octave::feval (meth.function_value (), args, 1);
373 if (lv.length () != 1 || ! lv(0).is_scalar_type ())
374 error ("@%s/numel: invalid return value", cn.c_str ());
375
376 retval = lv(0).idx_type_value (true);
377 }
378 else
379 retval = octave_base_value::xnumel (idx);
380
381 return retval;
382}
383
385octave_class::subsref (const std::string& type,
386 const std::list<octave_value_list>& idx,
387 int nargout)
388{
389 octave_value_list retval;
390
392 {
393 // FIXME: this block of code is the same as the body of
394 // octave_struct::subsref. Maybe it could be shared instead of
395 // duplicated.
396
397 int skip = 1;
398
399 switch (type[0])
400 {
401 case '(':
402 {
403 if (type.length () > 1 && type[1] == '.')
404 {
405 auto p = idx.begin ();
406 octave_value_list key_idx = *++p;
407
408 Cell tmp = dotref (key_idx);
409
410 Cell t = tmp.index (idx.front ());
411
412 retval(0) = (t.numel () == 1 ? t(0)
413 : octave_value (t, true));
414
415 // We handled two index elements, so tell
416 // next_subsref to skip both of them.
417 skip++;
418 }
419 else
420 retval(0) = octave_value (m_map.index (idx.front ()),
422 }
423 break;
424
425 case '.':
426 {
427 if (m_map.numel () > 0)
428 {
429 Cell t = dotref (idx.front ());
430
431 retval(0) = (t.numel () == 1) ? t(0) : octave_value (t, true);
432 }
433 }
434 break;
435
436 case '{':
437 err_invalid_index_type (type_name (), type[0]);
438 break;
439
440 default:
442 }
443
444 // FIXME: perhaps there should be an
445 // octave_value_list::next_subsref member function? See also
446 // octave_user_function::subsref.
447
448 if (idx.size () > 1)
449 retval = retval(0).next_subsref (nargout, type, idx, skip);
450 }
451 else
452 {
453 octave::symbol_table& symtab
454 = octave::__get_symbol_table__ ("octave_class::subsref");
455
456 octave_value meth = symtab.find_method ("subsref", class_name ());
457
458 if (meth.is_defined ())
459 {
461
462 args(1) = make_idx_args (type, idx, "subsref");
463
464 count++;
465 args(0) = octave_value (this);
466
467 // FIXME: for Matlab compatibility, let us attempt to set up a proper
468 // value for nargout at least in the simple case where the
469 // cs-list-type expression - i.e., {} or ().x, is the leading one.
470 // Note that Octave does not actually need this, since it will
471 // be able to properly react to varargout a posteriori.
472 bool maybe_cs_list_query = (type[0] == '.' || type[0] == '{'
473 || (type.length () > 1 && type[0] == '('
474 && type[1] == '.'));
475
476 int true_nargout = nargout;
477
478 if (maybe_cs_list_query)
479 {
480 // Set up a proper nargout for the subsref call by calling numel.
482 if (type[0] != '.') tmp = idx.front ();
483 true_nargout = xnumel (tmp);
484 }
485
486 retval = octave::feval (meth.function_value (), args, true_nargout);
487
488 // Since we're handling subsref, if the list has more than one
489 // element, return it as a comma-separated list so that we can
490 // pass it to the evaluator
491 if (retval.length () > 1)
492 retval = octave_value (retval);
493 }
494 else
495 {
496 if (type.length () == 1 && type[0] == '(')
497 retval(0) = octave_value (m_map.index (idx.front ()), c_name,
499 else
501 }
502 }
503
504 return retval;
505}
506
508octave_class::numeric_conv (const Cell& val, const std::string& type)
509{
510 octave_value retval;
511
512 if (val.numel () != 1)
514
515 retval = val(0);
516
517 if (type.length () > 0 && type[0] == '.' && ! retval.isstruct ())
518 retval = octave_map ();
519
520 return retval;
521}
522
524octave_class::subsasgn (const std::string& type,
525 const std::list<octave_value_list>& idx,
526 const octave_value& rhs)
527{
528 count++;
529 return subsasgn_common (octave_value (this), type, idx, rhs);
530}
531
533octave_class::undef_subsasgn (const std::string& type,
534 const std::list<octave_value_list>& idx,
535 const octave_value& rhs)
536{
537 // For compatibility with Matlab, pass [] as the first argument to the
538 // the subsasgn function when the LHS of an indexed assignment is
539 // undefined.
540
541 return subsasgn_common (Matrix (), type, idx, rhs);
542}
543
546 const std::string& type,
547 const std::list<octave_value_list>& idx,
548 const octave_value& rhs)
549{
550 octave_value retval;
551
552 if (! (in_class_method () || called_from_builtin ()))
553 {
554 octave::symbol_table& symtab
555 = octave::__get_symbol_table__ ("octave_class::subsasgn_common");
556
557 octave_value meth = symtab.find_method ("subsasgn", class_name ());
558
559 if (meth.is_defined ())
560 {
562
563 if (rhs.is_cs_list ())
564 {
565 octave_value_list lrhs = rhs.list_value ();
566 args.resize (2 + lrhs.length ());
567 for (octave_idx_type i = 0; i < lrhs.length (); i++)
568 args(2+i) = lrhs(i);
569 }
570 else
571 args(2) = rhs;
572
573 args(1) = make_idx_args (type, idx, "subsasgn");
574 args(0) = obj;
575
576 // Now comes the magic. Count copies with me:
577 // 1. myself (obsolete)
578 // 2. the copy inside args (obsolete)
579 // 3. the copy in method's symbol table (working)
580 // ... possibly more (not obsolete).
581 //
582 // So we mark 2 copies as obsolete and hold our fingers crossed.
583 // But prior to doing that, check whether the routine is amenable
584 // to the optimization.
585 // It is essential that the handling function doesn't store extra
586 // copies anywhere. If it does, things will not break but the
587 // optimization won't work.
588
590
591 if (m_obsolete_copies == 0 && meth.is_user_function ()
593 {
596
597 tmp = octave::feval (meth.function_value (), args);
598 }
599 else
600 tmp = octave::feval (meth.function_value (), args);
601
602 // FIXME: Should the subsasgn method be able to return
603 // more than one value?
604
605 if (tmp.length () > 1)
606 error ("@%s/subsasgn returned more than one value",
607 class_name ().c_str ());
608
609 else
610 retval = tmp(0);
611
612 return retval;
613 }
614 }
615
616 // Find the class in which this method resides before
617 // attempting to do the indexed assignment.
618
619 std::string method_class = get_current_method_class ();
620
621 octave_base_value *obvp = unique_parent_class (method_class);
622 if (obvp != this)
623 {
624
625 if (! obvp)
626 error ("malformed class");
627
628 obvp->subsasgn (type, idx, rhs);
629
630 count++;
631 retval = octave_value (this);
632
633 return retval;
634 }
635
636 // FIXME: this block of code is the same as the body of
637 // octave_struct::subsasgn. Maybe it could be shared instead of
638 // duplicated.
639
640 int n = type.length ();
641
642 octave_value t_rhs = rhs;
643
644 if (n > 1 && ! (type.length () == 2 && type[0] == '(' && type[1] == '.'))
645 {
646 switch (type[0])
647 {
648 case '(':
649 {
650 if (type.length () > 1 && type[1] == '.')
651 {
652 auto p = idx.begin ();
653 octave_value_list t_idx = *p;
654
655 octave_value_list key_idx = *++p;
656
657 assert (key_idx.length () == 1);
658
659 std::string key = key_idx(0).xstring_value ("invalid index for class assignment");
660
661 octave_value u;
662
663 if (! m_map.contains (key))
664 u = octave_value::empty_conv (type.substr (2), rhs);
665 else
666 {
667 Cell map_val = m_map.contents (key);
668
669 Cell map_elt = map_val.index (idx.front (), true);
670
671 u = numeric_conv (map_elt, type.substr (2));
672 }
673
674 std::list<octave_value_list> next_idx (idx);
675
676 // We handled two index elements, so subsasgn to
677 // needs to skip both of them.
678
679 next_idx.erase (next_idx.begin ());
680 next_idx.erase (next_idx.begin ());
681
682 u.make_unique ();
683
684 t_rhs = u.subsasgn (type.substr (2), next_idx, rhs);
685 }
686 else
688 }
689 break;
690
691 case '.':
692 {
693 octave_value_list key_idx = idx.front ();
694
695 assert (key_idx.length () == 1);
696
697 std::string key = key_idx(0).string_value ();
698
699 std::list<octave_value_list> next_idx (idx);
700
701 next_idx.erase (next_idx.begin ());
702
703 std::string next_type = type.substr (1);
704
705 Cell tmpc (1, 1);
706 auto pkey = m_map.seek (key);
707 if (pkey != m_map.end ())
708 {
709 m_map.contents (pkey).make_unique ();
710 tmpc = m_map.contents (pkey);
711 }
712
713 // FIXME: better code reuse?
714 if (tmpc.numel () != 1)
716
717 octave_value& tmp = tmpc(0);
718
719 if (! tmp.is_defined () || tmp.is_zero_by_zero ())
720 {
721 tmp = octave_value::empty_conv (next_type, rhs);
722 tmp.make_unique (); // probably a no-op.
723 }
724 else
725 // optimization: ignore copy still stored inside our map.
726 tmp.make_unique (1);
727
728 t_rhs = tmp.subsasgn (next_type, next_idx, rhs);
729 }
730 break;
731
732 case '{':
733 err_invalid_index_type (type_name (), type[0]);
734 break;
735
736 default:
738 }
739 }
740
741 switch (type[0])
742 {
743 case '(':
744 {
745 if (n > 1 && type[1] == '.')
746 {
747 auto p = idx.begin ();
748 octave_value_list key_idx = *++p;
749
750 assert (key_idx.length () == 1);
751
752 std::string key = key_idx(0).xstring_value ("assignment to class element failed");
753
754 m_map.assign (idx.front (), key, t_rhs);
755
756 count++;
757 retval = octave_value (this);
758 }
759 else
760 {
761 if (t_rhs.isobject () || t_rhs.isstruct ())
762 {
763 octave_map rhs_map = t_rhs.xmap_value ("invalid class assignment");
764
765 m_map.assign (idx.front (), rhs_map);
766
767 count++;
768 retval = octave_value (this);
769 }
770 else
771 {
772 if (! t_rhs.isempty ())
773 error ("invalid class assignment");
774
775 m_map.delete_elements (idx.front ());
776
777 count++;
778 retval = octave_value (this);
779 }
780 }
781 }
782 break;
783
784 case '.':
785 {
786 octave_value_list key_idx = idx.front ();
787
788 assert (key_idx.length () == 1);
789
790 std::string key = key_idx(0).string_value ();
791
792 if (t_rhs.is_cs_list ())
793 {
794 Cell tmp_cell = Cell (t_rhs.list_value ());
795
796 // The shape of the RHS is irrelevant, we just want
797 // the number of elements to agree and to preserve the
798 // shape of the left hand side of the assignment.
799
800 if (numel () == tmp_cell.numel ())
801 tmp_cell = tmp_cell.reshape (dims ());
802
803 m_map.setfield (key, tmp_cell);
804 }
805 else
806 {
807 Cell tmp_cell(1, 1);
808 tmp_cell(0) = t_rhs.storable_value ();
809 m_map.setfield (key, tmp_cell);
810 }
811
812 count++;
813 retval = octave_value (this);
814 }
815 break;
816
817 case '{':
818 err_invalid_index_type (type_name (), type[0]);
819 break;
820
821 default:
823 }
824
825 return retval;
826}
827
829octave_class::index_vector (bool require_integers) const
830{
831 octave::symbol_table& symtab
832 = octave::__get_symbol_table__ ("octave_class::index_vector");
833
834 octave_value meth = symtab.find_method ("subsindex", class_name ());
835
836 if (! meth.is_defined ())
837 error ("no subsindex method defined for class %s",
838 class_name ().c_str ());
839
842
843 octave_value_list tmp = octave::feval (meth.function_value (), args, 1);
844
845 if (tmp(0).isobject ())
846 error ("subsindex function must return a valid index vector");
847
848 // Index vector returned by subsindex is zero based
849 // (why this inconsistency Mathworks?), and so we must
850 // add one to the value returned as the index_vector method
851 // expects it to be one based.
853 octave_value (1.0)).index_vector (require_integers);
854}
855
856std::size_t
858{
859 // Neglect the size of the fieldnames.
860
861 std::size_t retval = 0;
862
863 for (auto it = m_map.cbegin (); it != m_map.cend (); it++)
864 {
865 std::string key = m_map.key (it);
866
868
869 retval += val.byte_size ();
870 }
871
872 return retval;
873}
874
875bool
877{
878 bool retval = false;
879
880 octave::symbol_table& symtab
881 = octave::__get_symbol_table__ ("octave_class::is_true");
882
883 octave_value meth = symtab.find_method ("logical", class_name ());
884
885 if (meth.is_defined ())
886 {
887 octave_value in = new octave_class (*this);
888
889 octave_value_list tmp = octave::feval (meth.function_value (), in, 1);
890 retval = tmp(0).is_true ();
891 }
892
893 return retval;
894}
895
898{
899 err_wrong_type_arg ("octave_class::map_keys()", type_name ());
900}
901
903octave_class::find_parent_class (const std::string& parent_class_name)
904{
905 octave_base_value *retval = nullptr;
906
907 if (parent_class_name == class_name ())
908 retval = this;
909 else
910 {
911 for (auto& par : m_parent_list)
912 {
914
915 const Cell& tmp = m_map.contents (smap);
916
917 octave_value vtmp = tmp(0);
918
919 octave_base_value *obvp = vtmp.internal_rep ();
920
921 retval = obvp->find_parent_class (parent_class_name);
922
923 if (retval)
924 break;
925 }
926 }
927
928 return retval;
929}
930
932octave_class::unique_parent_class (const std::string& parent_class_name)
933{
934 octave_base_value *retval = nullptr;
935
936 if (parent_class_name == class_name ())
937 retval = this;
938 else
939 {
940 for (auto& par : m_parent_list)
941 {
942 auto smap = m_map.seek (par);
943
944 Cell& tmp = m_map.contents (smap);
945
946 octave_value& vtmp = tmp(0);
947
948 octave_base_value *obvp = vtmp.internal_rep ();
949
950 // Use find_parent_class first to avoid uniquifying if not necessary.
951 retval = obvp->find_parent_class (parent_class_name);
952
953 if (retval)
954 {
955 vtmp.make_unique ();
956 obvp = vtmp.internal_rep ();
957 retval = obvp->unique_parent_class (parent_class_name);
958
959 break;
960 }
961 }
962 }
963
964 return retval;
965}
966
967bool
968octave_class::is_instance_of (const std::string& cls_name) const
969{
970 bool retval = false;
971
972 if (cls_name == class_name ())
973 retval = true;
974 else
975 {
976 for (auto& par : m_parent_list)
977 {
979
980 const Cell& tmp = m_map.contents (smap);
981
982 const octave_value& vtmp = tmp(0);
983
984 retval = vtmp.is_instance_of (cls_name);
985
986 if (retval)
987 break;
988 }
989 }
990
991 return retval;
992}
993
996{
997 string_vector retval;
998
999 octave::symbol_table& symtab
1000 = octave::__get_symbol_table__ ("octave_class::string_vector_value");
1001
1002 octave_value meth = symtab.find_method ("char", class_name ());
1003
1004 if (! meth.is_defined ())
1005 error ("no char method defined for class %s", class_name ().c_str ());
1006
1007 octave_value_list args;
1009
1010 octave_value_list tmp = octave::feval (meth.function_value (), args, 1);
1011
1012 if (tmp.length () >= 1)
1013 {
1014 if (! tmp(0).is_string ())
1015 error ("cname/char method did not return a string");
1016
1017 retval = tmp(0).string_vector_value (pad);
1018 }
1019
1020 return retval;
1021}
1022
1023void
1024octave_class::print (std::ostream& os, bool)
1025{
1026 print_raw (os);
1027}
1028
1029void
1030octave_class::print_raw (std::ostream& os, bool) const
1031{
1032 indent (os);
1033 os << " <class " << class_name () << '>';
1034 newline (os);
1035}
1036
1037// Loading a class properly requires an exemplar map entry for success.
1038// If we don't have one, we attempt to create one by calling the constructor
1039// with no arguments.
1040bool
1042{
1043 bool retval = false;
1044
1047
1048 if (it != octave_class::exemplar_map.end ())
1049 retval = true;
1050 else
1051 {
1052 octave::interpreter& interp
1053 = octave::__get_interpreter__ ("octave_class::reconstruct_exemplar");
1054
1055 octave::symbol_table& symtab = interp.get_symbol_table ();
1056
1057 octave_value ctor = symtab.find_method (c_name, c_name);
1058
1059 bool have_ctor = false;
1060
1061 if (ctor.is_defined () && ctor.is_function ())
1062 {
1063 octave_function *fcn = ctor.function_value ();
1064
1065 if (fcn && fcn->is_class_constructor (c_name))
1066 have_ctor = true;
1067
1068 // Something has gone terribly wrong if
1069 // symbol_table::find_method (c_name, c_name) does not return
1070 // a class constructor for the class c_name...
1071 assert (have_ctor);
1072 }
1073
1074 if (have_ctor)
1075 {
1077
1078 // Simulate try/catch.
1079
1081
1082 bool execution_error = false;
1083
1084 octave_value_list result;
1085
1086 try
1087 {
1088 result = octave::feval (ctor, ovl (), 1);
1089 }
1090 catch (const octave::execution_exception&)
1091 {
1092 interp.recover_from_exception ();
1093
1094 execution_error = true;
1095 }
1096
1097 if (! execution_error && result.length () == 1)
1098 retval = true;
1099 }
1100 else
1101 warning ("no constructor for class %s", c_name.c_str ());
1102 }
1103
1104 return retval;
1105}
1106
1107void
1109{
1110 exemplar_map.clear ();
1111}
1112
1113// Load/save does not provide enough information to reconstruct the
1114// class inheritance structure. reconstruct_parents () attempts to
1115// do so. If successful, a "true" value is returned.
1116//
1117// Note that we don't check the loaded object structure against the
1118// class structure here so the user's loadobj method has a chance
1119// to do its magic.
1120bool
1122{
1123 bool retval = true;
1124 bool might_have_inheritance = false;
1125 std::string dbgstr = "dork";
1126
1127 // First, check to see if there might be an issue with inheritance.
1128 for (auto it = m_map.cbegin (); it != m_map.cend (); it++)
1129 {
1130 std::string key = m_map.key (it);
1131 Cell val = m_map.contents (it);
1132 if (val(0).isobject ())
1133 {
1134 dbgstr = "blork";
1135 if (key == val(0).class_name ())
1136 {
1137 might_have_inheritance = true;
1138 dbgstr = "cork";
1139 break;
1140 }
1141 }
1142 }
1143
1144 if (might_have_inheritance)
1145 {
1148
1149 if (it == octave_class::exemplar_map.end ())
1150 retval = false;
1151 else
1152 {
1153 octave_class::exemplar_info exmplr = it->second;
1154 m_parent_list = exmplr.parents ();
1155 for (auto& par : m_parent_list)
1156 {
1157 dbgstr = par;
1158 bool dbgbool = m_map.contains (par);
1159 if (! dbgbool)
1160 {
1161 retval = false;
1162 break;
1163 }
1164 }
1165 }
1166 }
1167
1168 return retval;
1169}
1170
1171bool
1173{
1174 os << "# classname: " << class_name () << "\n";
1175 octave_map m;
1176
1177 octave::load_path& lp = octave::__get_load_path__ ("octave_class::save_ascii");
1178
1179 if (lp.find_method (class_name (), "saveobj") != "")
1180 {
1181 octave_value in = new octave_class (*this);
1182 octave_value_list tmp = octave::feval ("saveobj", in, 1);
1183
1184 m = tmp(0).map_value ();
1185 }
1186 else
1187 m = map_value ();
1188
1189 os << "# length: " << m.nfields () << "\n";
1190
1191 auto i = m.begin ();
1192 while (i != m.end ())
1193 {
1194 octave_value val = m_map.contents (i);
1195
1196 bool b = save_text_data (os, val, m.key (i), false, 0);
1197
1198 if (! b)
1199 return ! os.fail ();
1200
1201 i++;
1202 }
1203
1204 return true;
1205}
1206
1207bool
1209{
1210 octave_idx_type len = 0;
1211 std::string classname;
1212
1213 if (! extract_keyword (is, "classname", classname) || classname.empty ())
1214 error ("load: failed to extract name of class");
1215
1216 if (! extract_keyword (is, "length", len) || len < 0)
1217 error ("load: failed to extract number of elements in class");
1218
1219 if (len > 0)
1220 {
1221 octave_map m (m_map);
1222
1223 for (octave_idx_type j = 0; j < len; j++)
1224 {
1225 octave_value t2;
1226 bool dummy;
1227
1228 // recurse to read cell elements
1229 std::string nm
1230 = read_text_data (is, "", dummy, t2, j);
1231
1232 if (! is)
1233 break;
1234
1235 Cell tcell = (t2.iscell () ? t2.xcell_value ("load: internal error loading class elements") : Cell (t2));
1236
1237 m.assign (nm, tcell);
1238 }
1239
1240 if (! is)
1241 error ("load: failed to load class");
1242
1243 c_name = classname;
1245
1246 m_map = m;
1247
1248 if (! reconstruct_parents ())
1249 warning ("load: unable to reconstruct object inheritance");
1250
1251 octave::load_path& lp = octave::__get_load_path__ ("octave_class::load_ascii");
1252
1253 if (lp.find_method (classname, "loadobj") != "")
1254 {
1255 octave_value in = new octave_class (*this);
1256 octave_value_list tmp = octave::feval ("loadobj", in, 1);
1257
1258 m_map = tmp(0).map_value ();
1259 }
1260 }
1261 else if (len == 0)
1262 {
1263 m_map = octave_map (dim_vector (1, 1));
1264 c_name = classname;
1265 }
1266 else
1268
1269 return true;
1270}
1271
1272bool
1273octave_class::save_binary (std::ostream& os, bool save_as_floats)
1274{
1275 int32_t classname_len = class_name ().length ();
1276
1277 os.write (reinterpret_cast<char *> (&classname_len), 4);
1278 os << class_name ();
1279
1280 octave_map m;
1281
1282 octave::load_path& lp = octave::__get_load_path__ ("octave_class::save_binary");
1283
1284 if (lp.find_method (class_name (), "saveobj") != "")
1285 {
1286 octave_value in = new octave_class (*this);
1287 octave_value_list tmp = octave::feval ("saveobj", in, 1);
1288
1289 m = tmp(0).map_value ();
1290 }
1291 else
1292 m = map_value ();
1293
1294 int32_t len = m.nfields ();
1295 os.write (reinterpret_cast<char *> (&len), 4);
1296
1297 auto i = m.begin ();
1298 while (i != m.end ())
1299 {
1300 octave_value val = m_map.contents (i);
1301
1302 bool b = save_binary_data (os, val, m.key (i), "", 0, save_as_floats);
1303
1304 if (! b)
1305 return ! os.fail ();
1306
1307 i++;
1308 }
1309
1310 return true;
1311}
1312
1313bool
1314octave_class::load_binary (std::istream& is, bool swap,
1316{
1317 bool success = true;
1318
1319 int32_t classname_len;
1320
1321 is.read (reinterpret_cast<char *> (&classname_len), 4);
1322 if (! is)
1323 return false;
1324 else if (swap)
1325 swap_bytes<4> (&classname_len);
1326
1327 {
1328 OCTAVE_LOCAL_BUFFER (char, classname, classname_len+1);
1329 classname[classname_len] = '\0';
1330 if (! is.read (reinterpret_cast<char *> (classname), classname_len))
1331 return false;
1332 c_name = classname;
1333 }
1335
1336 int32_t len;
1337 if (! is.read (reinterpret_cast<char *> (&len), 4))
1338 return false;
1339 if (swap)
1340 swap_bytes<4> (&len);
1341
1342 if (len > 0)
1343 {
1344 octave_map m (m_map);
1345
1346 for (octave_idx_type j = 0; j < len; j++)
1347 {
1348 octave_value t2;
1349 bool dummy;
1350 std::string doc;
1351
1352 // recurse to read cell elements
1353 std::string nm = read_binary_data (is, swap, fmt, "",
1354 dummy, t2, doc);
1355
1356 if (! is)
1357 break;
1358
1359 Cell tcell = (t2.iscell () ? t2.xcell_value ("load: internal error loading class elements") : Cell (t2));
1360
1361 m.assign (nm, tcell);
1362 }
1363
1364 if (is)
1365 {
1366 m_map = m;
1367
1368 if (! reconstruct_parents ())
1369 warning ("load: unable to reconstruct object inheritance");
1370
1371 octave::load_path& lp = octave::__get_load_path__ ("octave_class::load_binary");
1372
1373 if (lp.find_method (c_name, "loadobj") != "")
1374 {
1375 octave_value in = new octave_class (*this);
1376 octave_value_list tmp = octave::feval ("loadobj", in, 1);
1377
1378 m_map = tmp(0).map_value ();
1379 }
1380 }
1381 else
1382 {
1383 warning ("load: failed to load class");
1384 success = false;
1385 }
1386 }
1387 else if (len == 0)
1388 m_map = octave_map (dim_vector (1, 1));
1389 else
1391
1392 return success;
1393}
1394
1395bool
1397 bool save_as_floats)
1398{
1399#if defined (HAVE_HDF5)
1400
1401 hsize_t hdims[3];
1402 hid_t group_hid = -1;
1403 hid_t type_hid = -1;
1404 hid_t space_hid = -1;
1405 hid_t class_hid = -1;
1406 hid_t data_hid = -1;
1407 octave_map m;
1409
1410 octave::load_path& lp = octave::__get_load_path__ ("octave_class::save_hdf5");
1411
1412#if defined (HAVE_HDF5_18)
1413 group_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT,
1415#else
1416 group_hid = H5Gcreate (loc_id, name, 0);
1417#endif
1418 if (group_hid < 0)
1419 goto error_cleanup;
1420
1421 // Add the class name to the group
1422 type_hid = H5Tcopy (H5T_C_S1); H5Tset_size (type_hid, c_name.length () + 1);
1423 if (type_hid < 0)
1424 goto error_cleanup;
1425
1426 hdims[0] = 0;
1427 space_hid = H5Screate_simple (0, hdims, nullptr);
1428 if (space_hid < 0)
1429 goto error_cleanup;
1430#if defined (HAVE_HDF5_18)
1431 class_hid = H5Dcreate (group_hid, "classname", type_hid, space_hid,
1434#else
1435 class_hid = H5Dcreate (group_hid, "classname", type_hid, space_hid,
1437#endif
1438 if (class_hid < 0 || H5Dwrite (class_hid, type_hid, octave_H5S_ALL,
1440 c_name.c_str ()) < 0)
1441 goto error_cleanup;
1442
1443#if defined (HAVE_HDF5_18)
1444 data_hid = H5Gcreate (group_hid, "value", octave_H5P_DEFAULT,
1446#else
1447 data_hid = H5Gcreate (group_hid, "value", 0);
1448#endif
1449 if (data_hid < 0)
1450 goto error_cleanup;
1451
1452 if (lp.find_method (class_name (), "saveobj") != "")
1453 {
1454 octave_value in = new octave_class (*this);
1455 octave_value_list tmp = octave::feval ("saveobj", in, 1);
1456
1457 m = tmp(0).map_value ();
1458 }
1459 else
1460 m = map_value ();
1461
1462 // recursively add each element of the class to this group
1463 i = m.begin ();
1464 while (i != m.end ())
1465 {
1466 octave_value val = m_map.contents (i);
1467
1468 bool retval2 = add_hdf5_data (data_hid, val, m.key (i), "", false,
1469 save_as_floats);
1470
1471 if (! retval2)
1472 break;
1473
1474 i++;
1475 }
1476
1477error_cleanup:
1478
1479 if (data_hid > 0)
1480 H5Gclose (data_hid);
1481
1482 if (class_hid > 0)
1483 H5Dclose (class_hid);
1484
1485 if (space_hid > 0)
1486 H5Sclose (space_hid);
1487
1488 if (type_hid > 0)
1489 H5Tclose (type_hid);
1490
1491 if (group_hid > 0)
1492 H5Gclose (group_hid);
1493
1494 return true;
1495
1496#else
1497 octave_unused_parameter (loc_id);
1498 octave_unused_parameter (name);
1499 octave_unused_parameter (save_as_floats);
1500
1501 warn_save ("hdf5");
1502
1503 return false;
1504#endif
1505}
1506
1507bool
1509{
1510 bool retval = false;
1511
1512#if defined (HAVE_HDF5)
1513
1514 hid_t group_hid = -1;
1515 hid_t data_hid = -1;
1516 hid_t type_hid = -1;
1517 hid_t type_class_hid = -1;
1518 hid_t space_hid = -1;
1519 hid_t subgroup_hid = -1;
1520 hid_t st_id = -1;
1521
1522 hdf5_callback_data dsub;
1523
1524 herr_t retval2 = 0;
1525 octave_map m (dim_vector (1, 1));
1526 int current_item = 0;
1527 hsize_t num_obj = 0;
1528 int slen = 0;
1529 hsize_t rank = 0;
1530
1531#if defined (HAVE_HDF5_18)
1532 group_hid = H5Gopen (loc_id, name, octave_H5P_DEFAULT);
1533#else
1534 group_hid = H5Gopen (loc_id, name);
1535#endif
1536 if (group_hid < 0)
1537 goto error_cleanup;
1538
1539#if defined (HAVE_HDF5_18)
1540 data_hid = H5Dopen (group_hid, "classname", octave_H5P_DEFAULT);
1541#else
1542 data_hid = H5Dopen (group_hid, "classname");
1543#endif
1544
1545 if (data_hid < 0)
1546 goto error_cleanup;
1547
1548 type_hid = H5Dget_type (data_hid);
1549
1550 type_class_hid = H5Tget_class (type_hid);
1551
1552 if (type_class_hid != H5T_STRING)
1553 goto error_cleanup;
1554
1555 space_hid = H5Dget_space (data_hid);
1556 rank = H5Sget_simple_extent_ndims (space_hid);
1557
1558 if (rank != 0)
1559 goto error_cleanup;
1560
1561 slen = H5Tget_size (type_hid);
1562 if (slen < 0)
1563 goto error_cleanup;
1564
1565 // do-while loop here to prevent goto crossing initialization of classname
1566 do
1567 {
1568 OCTAVE_LOCAL_BUFFER (char, classname, slen);
1569
1570 // create datatype for (null-terminated) string to read into:
1571 st_id = H5Tcopy (H5T_C_S1);
1572 H5Tset_size (st_id, slen);
1573
1574 if (H5Dread (data_hid, st_id, octave_H5S_ALL, octave_H5S_ALL,
1575 octave_H5P_DEFAULT, classname)
1576 < 0)
1577 {
1578 H5Tclose (st_id);
1579 H5Dclose (data_hid);
1580 H5Gclose (group_hid);
1581 return false;
1582 }
1583
1584 H5Tclose (st_id);
1585 H5Dclose (data_hid);
1586 data_hid = -1;
1587
1588 c_name = classname;
1589 }
1590 while (0);
1592
1593#if defined (HAVE_HDF5_18)
1594 subgroup_hid = H5Gopen (group_hid, name, octave_H5P_DEFAULT);
1595#else
1596 subgroup_hid = H5Gopen (group_hid, name);
1597#endif
1598 H5Gget_num_objs (subgroup_hid, &num_obj);
1599 H5Gclose (subgroup_hid);
1600
1601 while (current_item < static_cast<int> (num_obj)
1602 && (retval2 = hdf5_h5g_iterate (group_hid, name, &current_item,
1603 &dsub)) > 0)
1604 {
1605 octave_value t2 = dsub.tc;
1606
1607 Cell tcell = (t2.iscell () ? t2.xcell_value ("load: internal error loading class elements") : Cell (t2));
1608
1609 m.assign (dsub.name, tcell);
1610
1611 }
1612
1613 if (retval2 >= 0)
1614 {
1615 m_map = m;
1616
1617 if (! reconstruct_parents ())
1618 warning ("load: unable to reconstruct object inheritance");
1619
1620 octave::load_path& lp = octave::__get_load_path__ ("octave_class::load_hdf5");
1621
1622 if (lp.find_method (c_name, "loadobj") != "")
1623 {
1624 octave_value in = new octave_class (*this);
1625 octave_value_list tmp = octave::feval ("loadobj", in, 1);
1626
1627 m_map = tmp(0).map_value ();
1628 retval = true;
1629 }
1630 }
1631
1632error_cleanup:
1633 if (data_hid > 0)
1634 H5Dclose (data_hid);
1635
1636 if (data_hid > 0)
1637 H5Gclose (group_hid);
1638
1639#else
1640 octave_unused_parameter (loc_id);
1641 octave_unused_parameter (name);
1642
1643 warn_load ("hdf5");
1644#endif
1645
1646 return retval;
1647}
1648
1649mxArray *
1651{
1652 err_wrong_type_arg ("octave_class::as_mxArray ()", type_name ());
1653}
1654
1655bool
1657{
1658 octave::tree_evaluator& tw
1659 = octave::__get_evaluator__ ("octave_class::in_class_method");
1660
1661 octave_function *fcn = tw.current_function ();
1662
1663 return (fcn
1664 && (fcn->is_class_method ()
1665 || fcn->is_class_constructor ()
1668 && find_parent_class (fcn->dispatch_class ()));
1669}
1670
1672 : m_field_names (), m_parent_class_names ()
1673{
1674 if (! obj.isobject ())
1675 error ("invalid call to exemplar_info constructor");
1676
1677 octave_map m = obj.map_value ();
1678 m_field_names = m.keys ();
1679
1681}
1682
1683// A map from class names to lists of fields.
1684std::map<std::string, octave_class::exemplar_info> octave_class::exemplar_map;
1685
1686bool
1688{
1689
1690 if (! obj.isobject ())
1691 error ("invalid comparison of class exemplar to non-class object");
1692
1693 if (nfields () != obj.nfields ())
1694 error ("mismatch in number of fields");
1695
1696 octave_map obj_map = obj.map_value ();
1697 string_vector obj_fnames = obj_map.keys ();
1698 string_vector fnames = fields ();
1699
1700 for (octave_idx_type i = 0; i < nfields (); i++)
1701 {
1702 if (obj_fnames[i] != fnames[i])
1703 error ("mismatch in field names");
1704 }
1705
1706 if (nparents () != obj.nparents ())
1707 error ("mismatch in number of parent classes");
1708
1709 const std::list<std::string> obj_parents
1710 = obj.parent_class_name_list ();
1711 const std::list<std::string> pnames = parents ();
1712
1713 auto p = obj_parents.begin ();
1714 auto q = pnames.begin ();
1715
1716 while (p != obj_parents.end ())
1717 {
1718 if (*p++ != *q++)
1719 error ("mismatch in parent classes");
1720 }
1721
1722 return true;
1723}
1724
1725OCTAVE_NAMESPACE_BEGIN
1726
1727DEFMETHOD (class, interp, args, ,
1728 doc: /* -*- texinfo -*-
1729@deftypefn {} {@var{classname} =} class (@var{obj})
1730@deftypefnx {} {} class (@var{s}, @var{id})
1731@deftypefnx {} {} class (@var{s}, @var{id}, @var{p}, @dots{})
1732Return the class of the object @var{obj}, or create a class with
1733fields from structure @var{s} and name (string) @var{id}.
1734
1735Additional arguments name a list of parent classes from which the new class
1736is derived.
1737@seealso{typeinfo, isa}
1738@end deftypefn */)
1739{
1740 int nargin = args.length ();
1741
1742 if (nargin == 0)
1743 print_usage ();
1744
1745 octave_value retval;
1746
1747 if (nargin == 1)
1748 // Called for class of object
1749 retval = args(0).class_name ();
1750 else
1751 {
1752 // Called as class constructor
1753 std::string id = args(1).xstring_value ("class: ID (class name) must be a string");
1754
1755 tree_evaluator& tw = interp.get_evaluator ();
1756
1757 octave_function *fcn = tw.caller_function ();
1758
1759 if (! fcn)
1760 error ("class: invalid call from outside class constructor or method");
1761
1762 if (! fcn->is_class_constructor (id) && ! fcn->is_class_method (id))
1763 error ("class: '%s' is invalid as a class name in this context",
1764 id.c_str ());
1765
1766 octave_map m = args(0).xmap_value ("class: S must be a valid structure");
1767
1768 if (nargin == 2)
1769 retval
1770 = octave_value (new octave_class (m, id, std::list<std::string> ()));
1771 else
1772 {
1773 octave_value_list parents = args.slice (2, nargin-2);
1774
1775 retval = octave_value (new octave_class (m, id, parents));
1776 }
1777
1779 = octave_class::exemplar_map.find (id);
1780
1781 if (it == octave_class::exemplar_map.end ())
1783 else if (! it->second.compare (retval))
1784 error ("class: object of class '%s' does not match previously constructed objects",
1785 id.c_str ());
1786 }
1787
1788 return retval;
1789}
1790
1791/*
1792%!assert (class (1.1), "double")
1793%!assert (class (single (1.1)), "single")
1794%!assert (class (uint8 (1)), "uint8")
1795%!testif HAVE_JAVA; usejava ("jvm")
1796%! jobj = javaObject ("java.lang.StringBuffer");
1797%! assert (class (jobj), "java.lang.StringBuffer");
1798
1799## Test Input Validation
1800%!error class ()
1801*/
1802
1803DEFUN (isa, args, ,
1804 doc: /* -*- texinfo -*-
1805@deftypefn {} {} isa (@var{obj}, @var{classname})
1806Return true if @var{obj} is an object from the class @var{classname}.
1807
1808@var{classname} may also be one of the following class categories:
1809
1810@table @asis
1811@item @qcode{"float"}
1812Floating point value comprising classes @qcode{"double"} and
1813@qcode{"single"}.
1814
1815@item @qcode{"integer"}
1816Integer value comprising classes (u)int8, (u)int16, (u)int32, (u)int64.
1817
1818@item @qcode{"numeric"}
1819Numeric value comprising either a floating point or integer value.
1820@end table
1821
1822If @var{classname} is a cell array of string, a logical array of the same
1823size is returned, containing true for each class to which @var{obj}
1824belongs to.
1825
1826@seealso{class, typeinfo}
1827@end deftypefn */)
1828{
1829 if (args.length () != 2)
1830 print_usage ();
1831
1832 octave_value obj = args(0); // not const because of find_parent_class ()
1833 std::string obj_cls = obj.class_name ();
1834 Array<std::string> clsnames = args(1).xcellstr_value ("isa: CLASSNAME must be a string or cell array of strings");
1835
1836 boolNDArray matches (clsnames.dims (), false);
1837
1838 for (octave_idx_type idx = 0; idx < clsnames.numel (); idx++)
1839 {
1840 std::string cls = clsnames(idx);
1841 if (obj_cls == cls
1842 || (cls == "float" && obj.isfloat ())
1843 || (cls == "integer" && obj.isinteger ())
1844 || (cls == "numeric" && obj.isnumeric ())
1845 || obj.is_instance_of (cls))
1846 matches(idx) = true;
1847 }
1848
1849 return ovl (matches);
1850}
1851
1852/*
1853%!assert (isa ("char", "float"), false)
1854%!assert (isa (logical (1), "float"), false)
1855%!assert (isa (double (13), "float"), true)
1856%!assert (isa (single (13), "float"), true)
1857%!assert (isa (int8 (13), "float"), false)
1858%!assert (isa (int16 (13), "float"), false)
1859%!assert (isa (int32 (13), "float"), false)
1860%!assert (isa (int64 (13), "float"), false)
1861%!assert (isa (uint8 (13), "float"), false)
1862%!assert (isa (uint16 (13), "float"), false)
1863%!assert (isa (uint32 (13), "float"), false)
1864%!assert (isa (uint64 (13), "float"), false)
1865%!assert (isa ("char", "numeric"), false)
1866%!assert (isa (logical (1), "numeric"), false)
1867%!assert (isa (double (13), "numeric"), true)
1868%!assert (isa (single (13), "numeric"), true)
1869%!assert (isa (int8 (13), "numeric"), true)
1870%!assert (isa (int16 (13), "numeric"), true)
1871%!assert (isa (int32 (13), "numeric"), true)
1872%!assert (isa (int64 (13), "numeric"), true)
1873%!assert (isa (uint8 (13), "numeric"), true)
1874%!assert (isa (uint16 (13), "numeric"), true)
1875%!assert (isa (uint32 (13), "numeric"), true)
1876%!assert (isa (uint64 (13), "numeric"), true)
1877%!assert (isa (uint8 (13), "integer"), true)
1878%!assert (isa (double (13), "integer"), false)
1879%!assert (isa (single (13), "integer"), false)
1880%!assert (isa (single (13), {"integer", "float", "single"}), [false true true])
1881
1882%!assert (isa (double (13), "double"))
1883%!assert (isa (single (13), "single"))
1884%!assert (isa (int8 (13), "int8"))
1885%!assert (isa (int16 (13), "int16"))
1886%!assert (isa (int32 (13), "int32"))
1887%!assert (isa (int64 (13), "int64"))
1888%!assert (isa (uint8 (13), "uint8"))
1889%!assert (isa (uint16 (13), "uint16"))
1890%!assert (isa (uint32 (13), "uint32"))
1891%!assert (isa (uint64 (13), "uint64"))
1892%!assert (isa ("string", "char"))
1893%!assert (isa (true, "logical"))
1894%!assert (isa (false, "logical"))
1895%!assert (isa ({1, 2}, "cell"))
1896%!assert (isa ({1, 2}, {"numeric", "integer", "cell"}), [false false true])
1897
1898%!testif HAVE_JAVA; usejava ("jvm")
1899%! ## The first and last assert() are equal on purpose. The assert() in
1900%! ## the middle with an invalid class name will cause the java code to
1901%! ## throw exceptions which we then must clear properly (or all other calls
1902%! ## will fail). So we test this too.
1903%! assert (isa (javaObject ("java.lang.Double", 10), "java.lang.Number"));
1904%! assert (isa (javaObject ("java.lang.Double", 10), "not_a_class"), false);
1905%! assert (isa (javaObject ("java.lang.Double", 10), "java.lang.Number"));
1906
1907%!test
1908%! a.b = 1;
1909%! assert (isa (a, "struct"));
1910*/
1911
1912DEFUN (__parent_classes__, args, ,
1913 doc: /* -*- texinfo -*-
1914@deftypefn {} {} __parent_classes__ (@var{x})
1915Undocumented internal function.
1916@end deftypefn */)
1917{
1918 if (args.length () != 1)
1919 print_usage ();
1920
1921 octave_value arg = args(0);
1922
1923 if (arg.isobject ())
1924 return ovl (Cell (arg.parent_class_names ()));
1925 else
1926 return ovl (Cell ());
1927}
1928
1929DEFUN (isobject, args, ,
1930 doc: /* -*- texinfo -*-
1931@deftypefn {} {} isobject (@var{x})
1932Return true if @var{x} is a class object.
1933@seealso{class, typeinfo, isa, ismethod, isprop}
1934@end deftypefn */)
1935{
1936 if (args.length () != 1)
1937 print_usage ();
1938
1939 return ovl (args(0).isobject ());
1940}
1941
1942static bool
1943is_built_in_class (const std::string& cn)
1944{
1945 static std::set<std::string> built_in_class_names;
1946
1947 if (built_in_class_names.empty ())
1948 {
1949 built_in_class_names.insert ("double");
1950 built_in_class_names.insert ("single");
1951 built_in_class_names.insert ("cell");
1952 built_in_class_names.insert ("struct");
1953 built_in_class_names.insert ("logical");
1954 built_in_class_names.insert ("char");
1955 built_in_class_names.insert ("function handle");
1956 built_in_class_names.insert ("int8");
1957 built_in_class_names.insert ("uint8");
1958 built_in_class_names.insert ("int16");
1959 built_in_class_names.insert ("uint16");
1960 built_in_class_names.insert ("int32");
1961 built_in_class_names.insert ("uint32");
1962 built_in_class_names.insert ("int64");
1963 built_in_class_names.insert ("uint64");
1964 }
1965
1966 return built_in_class_names.find (cn) != built_in_class_names.end ();
1967}
1968
1969DEFMETHOD (superiorto, interp, args, ,
1970 doc: /* -*- texinfo -*-
1971@deftypefn {} {} superiorto (@var{class_name}, @dots{})
1972When called from a class constructor, mark the object currently constructed
1973as having a higher precedence than @var{class_name}.
1974
1975More that one such class can be specified in a single call. This function
1976may @emph{only} be called from a class constructor.
1977@seealso{inferiorto}
1978@end deftypefn */)
1979{
1980 tree_evaluator& tw = interp.get_evaluator ();
1981
1982 octave_function *fcn = tw.caller_function ();
1983
1984 if (! fcn || ! fcn->is_class_constructor ())
1985 error ("superiorto: invalid call from outside class constructor");
1986
1987 for (int i = 0; i < args.length (); i++)
1988 {
1989 std::string inf_class = args(i).xstring_value ("superiorto: CLASS_NAME must be a string");
1990
1991 // User defined classes always have higher precedence
1992 // than built-in classes
1993 if (is_built_in_class (inf_class))
1994 break;
1995
1996 symbol_table& symtab = interp.get_symbol_table ();
1997
1998 std::string sup_class = fcn->name ();
1999 if (! symtab.set_class_relationship (sup_class, inf_class))
2000 error ("superiorto: opposite precedence already set for %s and %s",
2001 sup_class.c_str (), inf_class.c_str ());
2002 }
2003
2004 return ovl ();
2005}
2006
2007DEFMETHOD (inferiorto, interp, args, ,
2008 doc: /* -*- texinfo -*-
2009@deftypefn {} {} inferiorto (@var{class_name}, @dots{})
2010When called from a class constructor, mark the object currently constructed
2011as having a lower precedence than @var{class_name}.
2012
2013More that one such class can be specified in a single call. This function
2014may @emph{only} be called from a class constructor.
2015@seealso{superiorto}
2016@end deftypefn */)
2017{
2018 tree_evaluator& tw = interp.get_evaluator ();
2019
2020 octave_function *fcn = tw.caller_function ();
2021
2022 if (! fcn || ! fcn->is_class_constructor ())
2023 error ("inferiorto: invalid call from outside class constructor");
2024
2025 for (int i = 0; i < args.length (); i++)
2026 {
2027 std::string sup_class = args(i).xstring_value ("inferiorto: CLASS_NAME must be a string");
2028
2029 if (is_built_in_class (sup_class))
2030 error ("inferiorto: cannot give user-defined class lower "
2031 "precedence than built-in class");
2032
2033 symbol_table& symtab = interp.get_symbol_table ();
2034
2035 std::string inf_class = fcn->name ();
2036 if (! symtab.set_class_relationship (sup_class, inf_class))
2037 error ("inferiorto: opposite precedence already set for %s and %s",
2038 inf_class.c_str (), sup_class.c_str ());
2039 }
2040
2041 return octave_value();
2042}
2043
2044// The following classes allow us to define "inline" function objects as
2045// legacy @class objects (as they appear to be in Matlab) while
2046// preserving the is_inline_function and function_value methods that
2047// were previously available in the octave_fcn_inline class. However,
2048// inline function objects no longer behave as octave_fcn_handle objects
2049// so calling is_function_handle for them no longer returns true. I see
2050// no reasonable way to preserve that behavior. The goal here is to
2051// allow most code that used the old octave_inline_fcn object to
2052// continue to work while eliminating the octave_inline_fcn class that
2053// was derived from the octave_fcn_handle class. Making that change
2054// appears to be necessary to properly fix function handle behavior and
2055// improve Matlab compatibility. It's unfortunate if this change causes
2056// trouble, but I see no better fix. Ultimately, we should replace all
2057// uses of "inline" function objects with anonymous functions.
2058
2059class octave_inline;
2060
2061// The following class can be removed once the
2062// octave_value::function_value method is removed.
2063
2064class
2066{
2067public:
2068
2069 octave_inline_fcn (octave_inline *obj) : m_inline_obj (obj) { }
2070
2071 // No copying!
2072
2074
2075 octave_inline_fcn& operator = (const octave_inline_fcn& ob) = delete;
2076
2077 ~octave_inline_fcn (void) = default;
2078
2079 // Override default call method because we ultimately use feval to
2080 // execute the inline function and that will push a stack frame.
2081
2083 call (tree_evaluator& tw, int nargout = 0,
2084 const octave_value_list& args = octave_value_list ())
2085 {
2086 return execute (tw, nargout, args);
2087 }
2088
2090 execute (tree_evaluator& tw, int nargout = 0,
2091 const octave_value_list& args = octave_value_list ());
2092
2093private:
2094
2096};
2097
2098// Once the octave_inline_fcn class is removed, we should also be able
2099// to eliminate the octave_inline class below and replace the
2100// octave_value::is_inline_function method with
2101//
2102// bool octave_value::is_inline_function (void) const
2103// {
2104// return class_name () == "inline";
2105// }
2106
2107class
2109{
2110public:
2111
2113 : octave_class (m, "inline"), m_fcn_obj (new octave_inline_fcn (this))
2114 { }
2115
2116 octave_inline (const octave_inline&) = default;
2117
2118 ~octave_inline (void) = default;
2119
2120 octave_base_value * clone (void) const { return new octave_inline (*this); }
2121
2123 {
2124 return new octave_inline (octave_map (map_keys ()));
2125 }
2126
2127 bool is_inline_function (void) const { return true; }
2128
2130 {
2131 return m_fcn_obj.get ();
2132 }
2133
2134private:
2135
2136 std::shared_ptr<octave_inline_fcn> m_fcn_obj;
2137};
2138
2141 const octave_value_list& args)
2142{
2143 interpreter& interp = tw.get_interpreter ();
2144
2145 return interp.feval (octave_value (m_inline_obj, true), args, nargout);
2146}
2147
2148
2149DEFUN (__inline_ctor__, args, ,
2150 doc: /* -*- texinfo -*-
2151@deftypefn {} {} __inline_ctor__ (@var{prop_struct})
2152Internal function.
2153
2154Implements final construction for inline objects.
2155@end deftypefn */)
2156{
2157 // Input validation has already been done in input.m.
2158
2159 return octave_value (new octave_inline (args(0).map_value ()));
2160}
2161
2162OCTAVE_NAMESPACE_END
bool isvector(const dim_vector &dim)
Definition: Array-util.cc:140
void swap_bytes< 4 >(void *ptr)
Definition: byte-swap.h:63
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
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
Definition: dMatrix.h:42
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:158
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
octave_idx_type ndims(void) const
Number of dimensions.
Definition: dim-vector.h:257
octave_value_list feval(const char *name, const octave_value_list &args=octave_value_list(), int nargout=0)
Evaluate an Octave function (built-in or interpreted) and return the list of result values.
octave::refcount< octave_idx_type > count
Definition: ov-base.h:906
virtual bool is_string(void) const
Definition: ov-base.h:417
virtual octave_map map_value(void) const
Definition: ov-base.cc:883
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
virtual octave_base_value * unique_parent_class(const std::string &)
Definition: ov-base.h:675
virtual octave_base_value * find_parent_class(const std::string &)
Definition: ov-base.h:672
virtual Matrix size(void)
Definition: ov-base.cc:185
virtual bool is_matrix_type(void) const
Definition: ov-base.h:483
OCTINTERP_API void warn_load(const char *type) const
Definition: ov-base.cc:1152
virtual bool is_scalar_type(void) const
Definition: ov-base.h:481
virtual octave_idx_type xnumel(const octave_value_list &)
Definition: ov-base.cc:195
virtual octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
Definition: ov-base.cc:240
static void register_type(void)
Definition: ov-base.cc:99
friend class octave_value
Definition: ov-base.h:256
OCTINTERP_API void warn_save(const char *type) const
Definition: ov-base.cc:1161
OCTINTERP_API bool compare(const octave_value &obj) const
Definition: ov-class.cc:1687
std::list< std::string > parents(void) const
Definition: ov-class.h:278
string_vector m_field_names
Definition: ov-class.h:284
std::list< std::string > m_parent_class_names
Definition: ov-class.h:285
OCTINTERP_API void print(std::ostream &os, bool pr_as_read_syntax=false)
Definition: ov-class.cc:1024
std::string type_name(void) const
Definition: ov-class.h:222
octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition: ov-class.h:104
OCTINTERP_API string_vector map_keys(void) const
Definition: ov-class.cc:897
OCTINTERP_API octave_base_value * unique_parent_class(const std::string &)
Definition: ov-class.cc:932
OCTINTERP_API octave_base_value * unique_clone(void)
Definition: ov-class.cc:209
OCTINTERP_API octave_idx_type xnumel(const octave_value_list &)
Definition: ov-class.cc:349
OCTINTERP_API octave_base_value * find_parent_class(const std::string &)
Definition: ov-class.cc:903
std::map< std::string, exemplar_info >::const_iterator exemplar_const_iterator
Definition: ov-class.h:294
OCTINTERP_API bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format fmt)
Definition: ov-class.cc:1314
OCTINTERP_API void print_raw(std::ostream &os, bool pr_as_read_syntax=false) const
Definition: ov-class.cc:1030
OCTINTERP_API std::size_t byte_size(void) const
Definition: ov-class.cc:857
OCTINTERP_API Cell dotref(const octave_value_list &idx)
Definition: ov-class.cc:282
OCTINTERP_API octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
Definition: ov-class.cc:524
std::string c_name
Definition: ov-class.h:234
std::list< std::string > m_parent_list
Definition: ov-class.h:235
OCTINTERP_API bool load_hdf5(octave_hdf5_id loc_id, const char *name)
Definition: ov-class.cc:1508
octave_map m_map
Definition: ov-class.h:218
static std::map< std::string, exemplar_info > exemplar_map
Definition: ov-class.h:289
octave_idx_type numel(void) const
Definition: ov-class.h:139
std::string class_name(void) const
Definition: ov-class.h:223
OCTINTERP_API octave_value subsasgn_common(const octave_value &obj, const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
Definition: ov-class.cc:545
OCTINTERP_API mxArray * as_mxArray(bool interleaved) const
Definition: ov-class.cc:1650
static const std::string t_name
Definition: ov-class.h:233
octave_map map_value(void) const
Definition: ov-class.h:171
OCTINTERP_API bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
Definition: ov-class.cc:1396
OCTINTERP_API bool in_class_method(void)
Definition: ov-class.cc:1656
OCTINTERP_API octave::idx_vector index_vector(bool require_integers=false) const
Definition: ov-class.cc:829
OCTINTERP_API bool save_ascii(std::ostream &os)
Definition: ov-class.cc:1172
void break_closure_cycles(const std::shared_ptr< octave::stack_frame > &frame)
Definition: ov-class.cc:270
std::size_t nparents(void) const
Definition: ov-class.h:147
static int t_id
Definition: ov-class.h:231
octave_class(void)
Definition: ov-class.h:57
int m_obsolete_copies
Definition: ov-class.h:245
OCTINTERP_API bool is_instance_of(const std::string &) const
Definition: ov-class.cc:968
OCTINTERP_API string_vector string_vector_value(bool pad) const
Definition: ov-class.cc:995
octave_idx_type nfields(void) const
Definition: ov-class.h:145
dim_vector dims(void) const
Definition: ov-class.h:133
OCTINTERP_API bool reconstruct_parents(void)
Definition: ov-class.cc:1121
OCTINTERP_API bool load_ascii(std::istream &is)
Definition: ov-class.cc:1208
OCTINTERP_API Matrix size(void)
Definition: ov-class.cc:309
OCTINTERP_API std::string get_current_method_class(void)
Definition: ov-class.cc:228
octave_base_value * clone(void) const
Definition: ov-class.h:82
bool isobject(void) const
Definition: ov-class.h:167
static OCTINTERP_API void clear_exemplar_map(void)
Definition: ov-class.cc:1108
OCTINTERP_API bool is_true(void) const
Definition: ov-class.cc:876
OCTINTERP_API bool save_binary(std::ostream &os, bool save_as_floats)
Definition: ov-class.cc:1273
OCTINTERP_API bool reconstruct_exemplar(void)
Definition: ov-class.cc:1041
static OCTINTERP_API octave_value numeric_conv(const Cell &val, const std::string &type)
Definition: ov-class.cc:508
OCTINTERP_API octave_value undef_subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
Definition: ov-class.cc:533
std::string dispatch_class(void) const
Definition: ov-fcn.h:149
virtual bool is_anonymous_function_of_class(const std::string &="") const
Definition: ov-fcn.h:168
bool is_class_method(const std::string &cname="") const
Definition: ov-fcn.h:116
bool is_class_constructor(const std::string &cname="") const
Definition: ov-fcn.h:111
bool is_private_function_of_class(const std::string &nm) const
Definition: ov-fcn.h:164
std::string name(void) const
Definition: ov-fcn.h:207
octave_value_list execute(tree_evaluator &tw, int nargout=0, const octave_value_list &args=octave_value_list())
Definition: ov-class.cc:2140
octave_inline_fcn(const octave_inline_fcn &ob)=delete
octave_inline_fcn(octave_inline *obj)
Definition: ov-class.cc:2069
octave_value_list call(tree_evaluator &tw, int nargout=0, const octave_value_list &args=octave_value_list())
Definition: ov-class.cc:2083
octave_inline * m_inline_obj
Definition: ov-class.cc:2095
~octave_inline_fcn(void)=default
octave_inline(const octave_inline &)=default
octave_inline(const octave_map &m)
Definition: ov-class.cc:2112
octave_function * function_value(bool)
Definition: ov-class.cc:2129
octave_base_value * clone(void) const
Definition: ov-class.cc:2120
~octave_inline(void)=default
bool is_inline_function(void) const
Definition: ov-class.cc:2127
octave_base_value * empty_clone(void) const
Definition: ov-class.cc:2122
std::shared_ptr< octave_inline_fcn > m_fcn_obj
Definition: ov-class.cc:2136
void resize(const dim_vector &dv, bool fill=false)
Definition: oct-map.cc:576
octave_idx_type nfields(void) const
Definition: oct-map.h:344
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
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 numel(void) const
Definition: oct-map.h:389
const_iterator seek(const std::string &k) const
Definition: oct-map.h:324
bool contains(const std::string &name) const
Definition: oct-map.h:350
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 iterator
Definition: oct-map.h:316
const_iterator begin(void) const
Definition: oct-map.h:318
const_iterator end(void) const
Definition: oct-map.h:319
string_vector keys(void) const
Definition: oct-map.h:356
const_iterator cbegin(void) const
Definition: oct-map.h:321
dim_vector dims(void) const
Definition: oct-map.h:430
octave_idx_type index(const_iterator p) const
Definition: oct-map.h:328
bool subsasgn_optimization_ok(void)
Definition: ov-usr-fcn.cc:515
void resize(octave_idx_type n, const octave_value &rfv=octave_value())
Definition: ovl.h:117
octave_idx_type length(void) const
Definition: ovl.h:113
octave_value_list slice(octave_idx_type offset, octave_idx_type len, bool tags=false) const
Definition: ovl.h:131
bool is_function(void) const
Definition: ov.h:822
bool iscell(void) const
Definition: ov.h:649
OCTINTERP_API octave_value_list list_value(void) const
OCTINTERP_API octave_function * function_value(bool silent=false) const
bool is_instance_of(const std::string &cls_name) const
Definition: ov.h:1086
octave::idx_vector index_vector(bool require_integers=false) const
Definition: ov.h:579
std::list< std::string > parent_class_name_list(void) const
Definition: ov.h:1076
OCTINTERP_API octave_user_function * user_function_value(bool silent=false) const
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())
bool isnumeric(void) const
Definition: ov.h:795
OCTINTERP_API Cell xcell_value(const char *fmt,...) const
octave_idx_type numel(void) const
Definition: ov.h:604
bool is_cs_list(void) const
Definition: ov.h:715
OCTINTERP_API octave_value storable_value(void) const
bool is_defined(void) const
Definition: ov.h:637
bool isinteger(void) const
Definition: ov.h:775
std::string class_name(void) const
Definition: ov.h:1451
bool isstruct(void) const
Definition: ov.h:694
bool is_zero_by_zero(void) const
Definition: ov.h:601
std::size_t byte_size(void) const
Definition: ov.h:607
octave_idx_type nfields(void) const
Definition: ov.h:614
string_vector parent_class_names(void) const
Definition: ov.h:1079
void make_unique(void)
Definition: ov.h:406
@ op_add
Definition: ov.h:91
bool isempty(void) const
Definition: ov.h:646
octave_base_value * internal_rep(void) const
Definition: ov.h:1508
OCTINTERP_API octave_map map_value(void) const
bool isobject(void) const
Definition: ov.h:709
std::size_t nparents(void) const
Definition: ov.h:1073
OCTINTERP_API octave_idx_type length(void) const
bool is_user_function(void) const
Definition: ov.h:828
OCTINTERP_API octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
bool isfloat(void) const
Definition: ov.h:746
dim_vector dims(void) const
Definition: ov.h:586
bool set_class_relationship(const std::string &sup_class, const std::string &inf_class)
Definition: symtab.cc:510
interpreter & get_interpreter(void)
Definition: pt-eval.h:414
octave_function * caller_function(void) const
Definition: pt-eval.cc:2523
const octave_hdf5_id octave_H5P_DEFAULT
const octave_hdf5_id octave_H5S_ALL
OCTINTERP_API void print_usage(void)
Definition: defun-int.h:72
#define DEFMETHOD(name, interp_name, args_name, nargout_name, doc)
Macro to define a builtin method.
Definition: defun.h:111
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void interpreter_try(unwind_protect &frame)
Definition: error.cc:2175
void warning(const char *fmt,...)
Definition: error.cc:1055
void error(const char *fmt,...)
Definition: error.cc:980
#define panic_impossible()
Definition: error.h:411
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:166
void err_indexed_cs_list(void)
Definition: errwarn.cc:65
QString name
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
OCTINTERP_API octave_value_list feval(const char *name, const octave_value_list &args=octave_value_list(), int nargout=0)
interpreter & __get_interpreter__(const std::string &who)
tree_evaluator & __get_evaluator__(const std::string &who)
load_path & __get_load_path__(const std::string &who)
symbol_table & __get_symbol_table__(const std::string &who)
int64_t octave_hdf5_id
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
octave_value make_idx_args(const std::string &type, const std::list< octave_value_list > &idx, const std::string &who)
Definition: ov-base.cc:1456
bool called_from_builtin(void)
Definition: ov-base.cc:1519
static OCTAVE_NORETURN void err_invalid_index_type(const std::string &nm, char t)
Definition: ov-class.cc:264
static OCTAVE_NORETURN void err_invalid_index1(void)
Definition: ov-class.cc:250
static OCTAVE_NORETURN void err_invalid_index_for_assignment(void)
Definition: ov-class.cc:257
static bool is_built_in_class(const std::string &cn)
Definition: ov-class.cc:1943
OCTINTERP_API octave_value binary_op(type_info &ti, octave_value::binary_op op, const octave_value &a, const octave_value &b)
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211
octave_value tc
Definition: ls-hdf5.h:115
std::string name
Definition: ls-hdf5.h:109
F77_RET_T len
Definition: xerbla.cc:61