GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
cdef-object.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2012-2021 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 "cdef-class.h"
31 #include "cdef-object.h"
32 #include "cdef-property.h"
33 #include "cdef-utils.h"
34 #include "interpreter.h"
35 #include "interpreter-private.h"
36 #include "ov-classdef.h"
37 
38 // Define to 1 to enable debugging statements.
39 #define DEBUG_TRACE 0
40 
41 namespace octave
42 {
43  void
45  {
46  // We need to be careful to keep a reference to the object if we are
47  // calling the delete method. The object is passed to the delete
48  // method as an argument and if the count is already zero when we
49  // do that, then we will increment the count while creating the
50  // argument list for the delete method and then it will be decremented
51  // back to zero and we'll find ourselves in an infinite loop.
52 
53  if (m_count - 1 > static_count ())
54  {
55  --m_count;
56  return;
57  }
58 
59  if (is_handle_object () && ! is_meta_object ())
60  {
61  unwind_protect frame;
62 
63  // Clear interrupts.
66 
67  // Disallow quit().
68  frame.protect_var (quit_allowed);
69  quit_allowed = false;
70 
71  interpreter& interp = __get_interpreter__ ("cdef_object_rep::release");
72 
73  interpreter_try (frame);
74 
75  try
76  {
77  // Call classdef "delete()" method on object
78  get_class ().delete_object (obj);
79  }
80  catch (const interrupt_exception&)
81  {
82  interp.recover_from_exception ();
83 
84  warning ("interrupt occurred in handle class delete method");
85  }
86  catch (const execution_exception& ee)
87  {
88  interp.recover_from_exception ();
89 
90  std::string msg = ee.message ();
91 
92  warning ("error caught while executing handle class delete method:\n%s\n",
93  msg.c_str ());
94  }
95  catch (const exit_exception&)
96  {
97  // This shouldn't happen since we disabled quit above.
98  warning ("exit disabled while executing handle class delete method");
99  }
100  catch (...) // Yes, the black hole. We're in a d-tor.
101  {
102  // This shouldn't happen, in theory.
103  warning ("internal error: unhandled exception in handle class delete method");
104  }
105  }
106 
107  // Now it is safe to set the count to zero.
108  m_count--;
109 
110  destroy ();
111  }
112 
113  cdef_class
115  {
116  err_invalid_object ("get_class");
117  }
118 
119  std::string
121  {
122  return get_class ().get_name ();
123  }
124 
127  {
128  cdef_class cls = get_class ();
129 
130  if (cls.ok ())
131  return cls.get_names ();
132 
133  return string_vector ();
134  }
135 
136  octave_map
138  {
140 
141  warning_with_id ("Octave:classdef-to-struct",
142  "struct: converting a classdef object into a struct "
143  "overrides the access restrictions defined for properties. "
144  "All properties are returned, including private and "
145  "protected ones.");
146 
147  cdef_class cls = get_class ();
148 
149  if (cls.ok ())
150  {
151  std::map<std::string, cdef_property> props;
152 
154 
155  // FIXME: Why not const here?
156  for (auto& prop_val : props)
157  {
158  if (is_array ())
159  {
160  Array<cdef_object> a_obj = array_value ();
161 
162  Cell cvalue (a_obj.dims ());
163 
164  for (octave_idx_type i = 0; i < a_obj.numel (); i++)
165  cvalue (i) = prop_val.second.get_value (a_obj(i), false);
166 
167  retval.setfield (prop_val.first, cvalue);
168  }
169  else
170  {
171  Cell cvalue (dim_vector (1, 1),
172  prop_val.second.get_value (*this, false));
173 
174  retval.setfield (prop_val.first, cvalue);
175  }
176  }
177  }
178 
179  return retval;
180  }
181 
182  cdef_class
184  {
185  return rep->get_class ();
186  }
187 
188  cdef_class
190  {
191  return cdef_class (klass);
192  }
193 
194  void
196  {
197  if ((klass.ok () && cls.ok () && cls != get_class ())
198  || (klass.ok () && ! cls.ok ())
199  || (! klass.ok () && cls.ok ()))
200  {
201  klass = cls;
202  }
203  }
204 
207  {
209 
210  r->set_class (get_class ());
211 
212  return r;
213  }
214 
216  cdef_object_array::subsref (const std::string& type,
217  const std::list<octave_value_list>& idx,
218  int /* nargout */, size_t& skip,
219  const cdef_class& /* context */, bool auto_add)
220  {
222 
223  skip = 1;
224 
225  switch (type[0])
226  {
227  case '(':
228  {
229  const octave_value_list& ival = idx.front ();
230 
231  if (ival.empty ())
232  {
233  m_count++;
234  retval(0) = to_ov (cdef_object (this));
235  break;
236  }
237 
238  bool is_scalar = true;
239  Array<idx_vector> iv (dim_vector (1, ival.length ()));
240 
241  for (int i = 0; i < ival.length (); i++)
242  {
243  try
244  {
245  iv(i) = ival(i).index_vector ();
246  }
247  catch (index_exception& e)
248  {
249  // Rethrow to allow more info to be reported later.
250  e.set_pos_if_unset (ival.length (), i+1);
251  throw;
252  }
253 
254  is_scalar = is_scalar && iv(i).is_scalar ();
255  }
256 
257  Array<cdef_object> ires = array.index (iv, auto_add);
258 
259  // If resizing is enabled (auto_add = true), it's possible
260  // indexing was out-of-bound and the result array contains
261  // invalid cdef_objects.
262 
263  if (auto_add)
264  fill_empty_values (ires);
265 
266  if (is_scalar)
267  retval(0) = to_ov (ires(0));
268  else
269  {
270  cdef_object array_obj (new cdef_object_array (ires));
271 
272  array_obj.set_class (get_class ());
273 
274  retval(0) = to_ov (array_obj);
275  }
276  }
277  break;
278 
279  case '.':
280  if (type.size () == 1 && idx.size () == 1)
281  {
282  Cell c (dims ());
283 
284  octave_idx_type n = array.numel ();
285 
286  // dummy variables
287  size_t dummy_skip;
288  cdef_class dummy_cls;
289 
290  for (octave_idx_type i = 0; i < n; i++)
291  {
292  octave_value_list r = array(i).subsref (type, idx, 1, dummy_skip,
293  dummy_cls);
294 
295  if (r.length () > 0)
296  c(i) = r(0);
297  }
298 
299  retval(0) = octave_value (c, true);
300 
301  break;
302  }
303  OCTAVE_FALLTHROUGH;
304 
305  default:
306  error ("can't perform indexing operation on array of %s objects",
307  class_name ().c_str ());
308  break;
309  }
310 
311  return retval;
312  }
313 
315  cdef_object_array::subsasgn (const std::string& type,
316  const std::list<octave_value_list>& idx,
317  const octave_value& rhs)
318  {
320 
321  switch (type[0])
322  {
323  case '(':
324  if (type.length () == 1)
325  {
326  cdef_object rhs_obj = to_cdef (rhs);
327 
328  if (rhs_obj.get_class () != get_class ())
329  error ("can't assign %s object into array of %s objects.",
330  rhs_obj.class_name ().c_str (),
331  class_name ().c_str ());
332 
333  const octave_value_list& ival = idx.front ();
334  bool is_scalar = true;
335  Array<idx_vector> iv (dim_vector (1, ival.length ()));
336 
337  for (int i = 0; i < ival.length (); i++)
338  {
339  try
340  {
341  iv(i) = ival(i).index_vector ();
342  }
343  catch (index_exception& e)
344  {
345  e.set_pos_if_unset (ival.length (), i+1);
346  throw; // var name set in pt-idx.cc / pt-assign.cc
347  }
348 
349  is_scalar = is_scalar && iv(i).is_scalar ();
350  }
351 
352  Array<cdef_object> rhs_mat;
353 
354  if (! rhs_obj.is_array ())
355  {
356  rhs_mat = Array<cdef_object> (dim_vector (1, 1));
357  rhs_mat(0) = rhs_obj;
358  }
359  else
360  rhs_mat = rhs_obj.array_value ();
361 
362  octave_idx_type n = array.numel ();
363 
364  array.assign (iv, rhs_mat, cdef_object ());
365 
366  if (array.numel () > n)
368 
369  m_count++;
370  retval = to_ov (cdef_object (this));
371  }
372  else
373  {
374  const octave_value_list& ivl = idx.front ();
375 
376  // Fill in trailing singleton dimensions so that
377  // array.index doesn't create a new blank entry (bug #46660).
378  const octave_idx_type one = static_cast<octave_idx_type> (1);
379  const octave_value_list& ival = ivl.length () >= 2
380  ? ivl : ((array.dims ()(0) == 1)
381  ? ovl (one, ivl(0))
382  : ovl (ivl(0), one));
383 
384  bool is_scalar = true;
385 
386  Array<idx_vector> iv (dim_vector (1, ival.length ()));
387 
388  for (int i = 0; i < ival.length (); i++)
389  {
390  try
391  {
392  iv(i) = ival(i).index_vector ();
393  }
394  catch (index_exception& e)
395  {
396  // Rethrow to allow more info to be reported later.
397  e.set_pos_if_unset (ival.length (), i+1);
398  throw;
399  }
400 
401  is_scalar = is_scalar && iv(i).is_scalar ();
402 
403  if (! is_scalar)
404  error ("subsasgn: invalid indexing for object array assignment"
405  ", the index must reference a single object in the "
406  "array.");
407  }
408 
409  Array<cdef_object> a = array.index (iv, true);
410 
411  if (a.numel () != 1)
412  error ("subsasgn: invalid indexing for object array assignment");
413 
414  cdef_object obj = a(0);
415 
416  int ignore_copies = 0;
417 
418  // If the object in 'a' is not valid, this means the index
419  // was out-of-bound and we need to create a new object.
420 
421  if (! obj.ok ())
423  else
424  // Optimize the subsasgn call to come. There are 2 copies
425  // that we can safely ignore:
426  // - 1 in "array"
427  // - 1 in "a"
428  ignore_copies = 2;
429 
430  std::list<octave_value_list> next_idx (idx);
431 
432  next_idx.erase (next_idx.begin ());
433 
434  octave_value tmp = obj.subsasgn (type.substr (1), next_idx,
435  rhs, ignore_copies);
436 
437  cdef_object robj = to_cdef (tmp);
438 
439  if (! robj.ok ()
440  || robj.is_array ()
441  || robj.get_class () != get_class ())
442  error ("subsasgn: invalid assignment into array of %s objects",
443  class_name ().c_str ());
444 
445  // Small optimization, when dealing with handle
446  // objects, we don't need to re-assign the result
447  // of subsasgn back into the array.
448 
449  if (! robj.is (a(0)))
450  {
451  Array<cdef_object> rhs_a (dim_vector (1, 1),
452  robj);
453 
454  octave_idx_type n = array.numel ();
455 
456  array.assign (iv, rhs_a);
457 
458  if (array.numel () > n)
460  }
461 
462  m_count++;
463 
464  retval = to_ov (cdef_object (this));
465  }
466  break;
467 
468  default:
469  error ("can't perform indexing operation on array of %s objects",
470  class_name ().c_str ());
471  break;
472  }
473 
474  return retval;
475  }
476 
477  void
479  {
480  cdef_class cls = get_class ();
481 
482  cdef_object obj;
483 
484  int n = arr.numel ();
485 
486  for (int i = 0; i < n; i++)
487  {
488  if (! arr.xelem (i).ok ())
489  {
490  if (! obj.ok ())
491  {
492  obj = cls.construct_object (octave_value_list ());
493 
494  arr.xelem (i) = obj;
495  }
496  else
497  arr.xelem (i) = obj.copy ();
498  }
499  }
500  }
501 
503  cdef_object_scalar::subsref (const std::string& type,
504  const std::list<octave_value_list>& idx,
505  int nargout, size_t& skip,
506  const cdef_class& context, bool auto_add)
507  {
508  skip = 0;
509 
510  cdef_class cls = (context.ok () ? context : get_class ());
511 
513 
514  if (! cls.ok ())
515  return retval;
516 
517  switch (type[0])
518  {
519  case '.':
520  {
521  std::string name = (idx.front ())(0).string_value ();
522 
523  cdef_method meth = cls.find_method (name);
524 
525  if (meth.ok ())
526  {
527  int _nargout = (type.length () > 2 ? 1 : nargout);
528 
529  octave_value_list args;
530 
531  skip = 1;
532 
533  if (type.length () > 1 && type[1] == '(')
534  {
535  auto it = idx.begin ();
536 
537  args = *++it;
538 
539  skip++;
540  }
541 
542  if (meth.is_static ())
543  retval = meth.execute (args, _nargout, true, "subsref");
544  else
545  {
546  m_count++;
547  retval = meth.execute (cdef_object (this), args, _nargout,
548  true, "subsref");
549  }
550  }
551 
552  if (skip == 0)
553  {
554  cdef_property prop = cls.find_property (name);
555 
556  if (! prop.ok ())
557  error ("subsref: unknown method or property: %s", name.c_str ());
558 
559  if (prop.is_constant ())
560  retval(0) = prop.get_value (true, "subsref");
561  else
562  {
563  m_count++;
564  retval(0) = prop.get_value (cdef_object (this),
565  true, "subsref");
566  }
567 
568  skip = 1;
569  }
570  break;
571  }
572 
573  case '(':
574  {
575  const octave_value_list& ival = idx.front ();
576 
577  m_count++;
578  cdef_object this_obj (this);
579 
580  if (ival.empty ())
581  {
582  skip++;
583  retval(0) = to_ov (this_obj);
584  }
585  else
586  {
587  Array<cdef_object> arr (dim_vector (1, 1), this_obj);
588 
589  cdef_object new_obj = cdef_object (new cdef_object_array (arr));
590 
591  new_obj.set_class (get_class ());
592 
593  retval = new_obj.subsref (type, idx, nargout, skip, cls, auto_add);
594  }
595  }
596  break;
597 
598  default:
599  error ("object cannot be indexed with '%c'", type[0]);
600  break;
601  }
602 
603  return retval;
604  }
605 
607  cdef_object_scalar::subsasgn (const std::string& type,
608  const std::list<octave_value_list>& idx,
609  const octave_value& rhs)
610  {
612 
613  cdef_class cls = get_class ();
614 
615  switch (type[0])
616  {
617  case '.':
618  {
619  std::string name = (idx.front ())(0).string_value ();
620 
621  cdef_property prop = cls.find_property (name);
622 
623  if (! prop.ok ())
624  error ("subsasgn: unknown property: %s", name.c_str ());
625 
626  if (prop.is_constant ())
627  error ("subsasgn: cannot assign constant property: %s",
628  name.c_str ());
629 
630  m_count++;
631 
632  cdef_object obj (this);
633 
634  if (type.length () == 1)
635  {
636  prop.set_value (obj, rhs, true, "subsasgn");
637 
638  retval = to_ov (obj);
639  }
640  else
641  {
642  octave_value val = prop.get_value (obj, true, "subsasgn");
643 
644  std::list<octave_value_list> args (idx);
645 
646  args.erase (args.begin ());
647 
648  val = val.assign (octave_value::op_asn_eq,
649  type.substr (1), args, rhs);
650 
651  if (val.class_name () != "object"
652  || ! to_cdef (val).is_handle_object ())
653  prop.set_value (obj, val, true, "subsasgn");
654 
655  retval = to_ov (obj);
656  }
657  }
658  break;
659 
660  case '(':
661  {
662  m_count++;
663 
664  cdef_object this_obj (this);
665 
666  Array<cdef_object> arr (dim_vector (1, 1), this_obj);
667 
668  cdef_object new_obj = cdef_object (new cdef_object_array (arr));
669 
670  new_obj.set_class (get_class ());
671 
672  octave_value tmp = new_obj.subsasgn (type, idx, rhs);
673 
674  retval = tmp;
675  }
676  break;
677 
678  default:
679  error ("subsasgn: object cannot be index with '%c'", type[0]);
680  break;
681  }
682 
683  return retval;
684  }
685 
686  void
688  {
689  std::string cls_name = cls.get_name ();
690 
691  Cell supcls = cls.get ("SuperClasses").cell_value ();
692 
693  std::list<cdef_class> supcls_list = lookup_classes (supcls);
694 
695  ctor_list[cls] = supcls_list;
696  }
697 
698  bool
700  {
701  return (is_constructed ()
702  || ctor_list.find (cls) == ctor_list.end ());
703  }
704 
705  bool
707  {
708  if (is_constructed ())
709  return true;
710 
711  std::map<cdef_class, std::list<cdef_class>>::const_iterator it
712  = ctor_list.find (cls);
713 
714  if (it == ctor_list.end () || it->second.empty ())
715  return true;
716 
717  for (const auto& cdef_cls : it->second)
718  if (! is_partially_constructed_for (cdef_cls))
719  return false;
720 
721  return true;
722  }
723 
724  void
726  {
727  ctor_list.erase (cls);
728  }
729 
731  {
732 #if DEBUG_TRACE
733  std::cerr << "deleting " << get_class ().get_name ()
734  << " object (handle)" << std::endl;
735 #endif
736  }
737 
739  {
740 #if DEBUG_TRACE
741  std::cerr << "deleting " << get_class ().get_name ()
742  << " object (value)" << std::endl;
743 #endif
744  }
745 }
bool is_scalar(const dim_vector &dim)
Definition: Array-util.cc:116
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:128
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:469
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:377
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:453
Definition: Cell.h:43
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
void delete_object(const cdef_object &obj)
Definition: cdef-class.h:308
cdef_method find_method(const std::string &nm, bool local=false)
Definition: cdef-class.h:438
cdef_property find_property(const std::string &nm)
Definition: cdef-class.h:444
string_vector get_names(void)
Definition: cdef-class.h:288
std::map< std::string, cdef_property > get_property_map(int mode=property_normal)
Definition: cdef-class.h:283
std::string get_name(void) const
Definition: cdef-class.h:304
cdef_object construct_object(const octave_value_list &args)
Definition: cdef-class.h:354
octave_value_list execute(const octave_value_list &args, int nargout, bool do_check_access=true, const std::string &who="")
Definition: cdef-method.h:163
bool is_static(void) const
Definition: cdef-method.h:183
octave_value_list subsref(const std::string &type, const std::list< octave_value_list > &idx, int nargout, size_t &skip, const cdef_class &context, bool auto_add)
Definition: cdef-object.cc:216
octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
Definition: cdef-object.cc:315
Array< cdef_object > array
Definition: cdef-object.h:433
dim_vector dims(void) const
Definition: cdef-object.h:398
cdef_class get_class(void) const
Definition: cdef-object.cc:189
cdef_object_rep * make_array(void) const
Definition: cdef-object.cc:206
void set_class(const cdef_class &cls)
Definition: cdef-object.cc:195
virtual octave_idx_type static_count(void) const
Definition: cdef-object.h:172
void release(const cdef_object &obj)
Definition: cdef-object.cc:44
virtual void destroy(void)
Definition: cdef-object.h:174
refcount< octave_idx_type > m_count
Definition: cdef-object.h:183
virtual bool is_handle_object(void) const
Definition: cdef-object.h:94
OCTAVE_NORETURN void err_invalid_object(const char *who) const
Definition: cdef-object.h:191
std::string class_name(void) const
Definition: cdef-object.cc:120
virtual cdef_class get_class(void) const
Definition: cdef-object.cc:114
friend class cdef_object
Definition: cdef-object.h:55
virtual string_vector map_keys(void) const
Definition: cdef-object.cc:126
virtual bool is_meta_object(void) const
Definition: cdef-object.h:96
bool is_constructed_for(const cdef_class &cls) const
Definition: cdef-object.cc:699
bool is_constructed(void) const
Definition: cdef-object.h:510
octave_value_list subsref(const std::string &type, const std::list< octave_value_list > &idx, int nargout, size_t &skip, const cdef_class &context, bool auto_add)
Definition: cdef-object.cc:503
bool is_partially_constructed_for(const cdef_class &cls) const
Definition: cdef-object.cc:706
void mark_for_construction(const cdef_class &)
Definition: cdef-object.cc:687
std::map< cdef_class, std::list< cdef_class > > ctor_list
Definition: cdef-object.h:518
octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
Definition: cdef-object.cc:607
octave_value_list subsref(const std::string &type, const std::list< octave_value_list > &idx, int nargout, size_t &skip, const cdef_class &context, bool auto_add=false)
Definition: cdef-object.h:279
bool is(const cdef_object &obj) const
Definition: cdef-object.h:324
void set_class(const cdef_class &cls)
Definition: cdef-object.h:226
bool ok(void) const
Definition: cdef-object.h:300
std::string class_name(void) const
Definition: cdef-object.h:228
cdef_class get_class(void) const
Definition: cdef-object.cc:183
octave_map map_value(void) const
Definition: cdef-object.cc:137
octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs, int ignore_copies=0)
Definition: cdef-object.h:287
Array< cdef_object > array_value(void) const
Definition: cdef-object.h:254
octave_value get(const std::string &pname) const
Definition: cdef-object.h:261
cdef_object copy(void) const
Definition: cdef-object.h:244
bool is_array(void) const
Definition: cdef-object.h:246
cdef_object_rep * rep
Definition: cdef-object.h:338
void set_value(cdef_object &obj, const octave_value &val, bool do_check_access=true, const std::string &who="")
octave_value get_value(const cdef_object &obj, bool do_check_access=true, const std::string &who="") const
bool is_constant(void) const
void set_pos_if_unset(octave_idx_type nd_arg, octave_idx_type dim_arg)
void recover_from_exception(void)
bool empty(void) const
Definition: ovl.h:115
octave_idx_type length(void) const
Definition: ovl.h:113
Cell cell_value(void) const
std::string class_name(void) const
Definition: ov.h:1256
@ op_asn_eq
Definition: ov.h:139
octave_value & assign(assign_op op, const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
void warning(const char *fmt,...)
Definition: error.cc:1050
void interpreter_try(octave::unwind_protect &frame)
Definition: error.cc:2182
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:1065
void error(const char *fmt,...)
Definition: error.cc:968
QString name
bool quit_allowed
Definition: interpreter.cc:85
octave_idx_type n
Definition: mx-inlines.cc:753
T * r
Definition: mx-inlines.cc:773
std::list< cdef_class > lookup_classes(const Cell &cls_list)
Definition: cdef-utils.cc:113
octave_value to_ov(const cdef_object &obj)
Definition: cdef-utils.cc:128
cdef_object to_cdef(const octave_value &val)
Definition: cdef-utils.cc:143
static llvm::LLVMContext & context
Definition: jit-typeinfo.cc:80
interpreter & __get_interpreter__(const std::string &who)
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211
sig_atomic_t octave_interrupt_state
Definition: quit.cc:38