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