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