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