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