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