GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ov-fcn-handle.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2003-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 <istream>
31 #include <list>
32 #include <ostream>
33 #include <sstream>
34 #include <string>
35 #include <vector>
36 
37 #include "file-ops.h"
38 #include "oct-locbuf.h"
39 
40 #include "defaults.h"
41 #include "defun.h"
42 #include "error.h"
43 #include "errwarn.h"
44 #include "file-stat.h"
45 #include "input.h"
46 #include "interpreter-private.h"
47 #include "interpreter.h"
48 #include "load-path.h"
49 #include "oct-env.h"
50 #include "oct-hdf5.h"
51 #include "oct-map.h"
52 #include "ov-base.h"
53 #include "ov-cell.h"
54 #include "ov-fcn-handle.h"
55 #include "ov-usr-fcn.h"
56 #include "parse.h"
57 #include "pr-output.h"
58 #include "pt-arg-list.h"
59 #include "pt-assign.h"
60 #include "pt-cmd.h"
61 #include "pt-eval.h"
62 #include "pt-exp.h"
63 #include "pt-idx.h"
64 #include "pt-misc.h"
65 #include "pt-pr-code.h"
66 #include "pt-stmt.h"
67 #include "stack-frame.h"
68 #include "syminfo.h"
69 #include "symscope.h"
70 #include "unwind-prot.h"
71 #include "variables.h"
72 
73 #include "byte-swap.h"
74 #include "ls-ascii-helper.h"
75 #include "ls-hdf5.h"
76 #include "ls-oct-text.h"
77 #include "ls-oct-binary.h"
78 #include "ls-utils.h"
79 
80 
82  "function handle",
83  "function_handle");
84 
85 const std::string octave_fcn_handle::anonymous ("@<anonymous>");
86 
87 namespace octave
88 {
90  {
91  public:
92 
93  invalid_fcn_handle (void) : base_fcn_handle ("<invalid>") { }
94 
96 
97  ~invalid_fcn_handle (void) = default;
98 
99  invalid_fcn_handle * clone (void) const
100  {
101  return new invalid_fcn_handle (*this);
102  }
103 
104  std::string type (void) const { return "<invalid>"; }
105 
106  octave_value_list call (int nargout, const octave_value_list& args);
107  };
108 
109  // Create a handle to an unnamed internal function. There will be no
110  // way to save and reload it. See, for example, the F__fltk_check__
111  // function in __init_fltk__.cc.
112 
114  {
115  public:
116 
118  : base_fcn_handle ("<internal>"), m_fcn (fcn)
119  { }
120 
122 
123  ~internal_fcn_handle (void) = default;
124 
125  internal_fcn_handle * clone (void) const
126  {
127  return new internal_fcn_handle (*this);
128  }
129 
130  std::string type (void) const { return "<internal>"; }
131 
132  bool is_internal (void) const { return true; }
133 
134  octave_value_list call (int nargout, const octave_value_list& args);
135 
136  // FIXME: These must go away. They don't do the right thing for
137  // scoping or overloads.
139  {
140  return m_fcn.function_value ();
141  }
142 
144  {
145  return m_fcn.user_function_value ();
146  }
147 
148  octave_value fcn_val (void) { return m_fcn; }
149 
150  // Should be const.
151  octave_scalar_map info (void);
152 
153  friend bool is_equal_to (const internal_fcn_handle& fh1,
154  const internal_fcn_handle& fh2);
155 
156  private:
157 
159  };
160 
162  {
163  public:
164 
165  // FIXME: octaveroot is temporary information used when loading
166  // handles. Can we avoid using it in the constructor?
167 
168  simple_fcn_handle (const std::string& name = "",
169  const std::string& file = "",
170  const std::string& /*octaveroot*/ = "")
171  : base_fcn_handle (name, file), m_fcn ()
172  { }
173 
174  simple_fcn_handle (const octave_value& fcn, const std::string& name)
175  : base_fcn_handle (name), m_fcn (fcn)
176  {
177  if (m_fcn.is_defined ())
178  {
179  octave_function *oct_fcn = m_fcn.function_value ();
180 
181  if (oct_fcn)
182  m_file = oct_fcn->fcn_file_name ();
183  }
184  }
185 
187 
188  ~simple_fcn_handle (void) = default;
189 
190  simple_fcn_handle * clone (void) const
191  {
192  return new simple_fcn_handle (*this);
193  }
194 
195  std::string type (void) const { return "simple"; }
196 
197  bool is_simple (void) const { return true; }
198 
199  octave_value_list call (int nargout, const octave_value_list& args);
200 
201  // FIXME: These must go away. They don't do the right thing for
202  // scoping or overloads.
204 
206 
207  octave_value fcn_val (void);
208 
209  // Should be const.
210  octave_scalar_map info (void);
211 
212  bool save_ascii (std::ostream& os);
213 
214  bool load_ascii (std::istream& is);
215 
216  bool save_binary (std::ostream& os, bool save_as_floats);
217 
218  bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
219 
220  bool save_hdf5 (octave_hdf5_id loc_hid, const char *name, bool save_as_floats);
221 
222  bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
223  octave_hdf5_id& type_hid);
224 
225  void print_raw (std::ostream& os, bool pr_as_read_syntax,
226  int current_print_indent_level) const;
227 
228  friend bool is_equal_to (const simple_fcn_handle& fh1,
229  const simple_fcn_handle& fh2);
230 
231  private:
232 
234  };
235 
237  {
238  public:
239 
240  // FIXME: octaveroot is temporary information used when loading
241  // handles. Can we avoid using it in the constructor?
242 
243  scoped_fcn_handle (const std::string& name = "",
244  const std::string& file = "",
245  const std::string& /*octaveroot*/ = "")
247  { }
248 
249  scoped_fcn_handle (const octave_value& fcn, const std::string& name,
250  const std::list<std::string>& parentage);
251 
253 
254  ~scoped_fcn_handle (void) = default;
255 
256  scoped_fcn_handle * clone (void) const
257  {
258  return new scoped_fcn_handle (*this);
259  }
260 
261  std::string type (void) const { return "scopedfunction"; }
262 
263  bool is_scoped (void) const { return true; }
264 
265  octave_value_list call (int nargout, const octave_value_list& args);
266 
267  // FIXME: These must go away. They don't do the right thing for
268  // scoping or overloads.
270  {
271  return m_fcn.function_value ();
272  }
273 
275  {
276  return m_fcn.user_function_value ();
277  }
278 
279  octave_value fcn_val (void) { return m_fcn; }
280 
281  // Should be const.
282  octave_scalar_map info (void);
283 
284  bool save_ascii (std::ostream& os);
285 
286  bool load_ascii (std::istream& is);
287 
288  bool save_binary (std::ostream& os, bool save_as_floats);
289 
290  bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
291 
292  bool save_hdf5 (octave_hdf5_id loc_id, const char *name, bool save_as_floats);
293 
294  bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
295  octave_hdf5_id& type_hid);
296 
297  void print_raw (std::ostream&, bool pr_as_read_syntax,
298  int current_print_indent_level) const;
299 
300  friend bool is_equal_to (const scoped_fcn_handle& fh1,
301  const scoped_fcn_handle& fh2);
302 
303  protected:
304 
305  void find_function (void);
306 
307  // The function we are handling.
309 
310  // List of parent function names. The first element is the name of
311  // m_fcn.
312  std::list<std::string> m_parentage;
313  };
314 
316  {
317  public:
318 
319  // FIXME: octaveroot is temporary information used when loading
320  // handles. Can we avoid using it in the constructor?
321 
322  nested_fcn_handle (const std::string& name = "",
323  const std::string& file = "",
324  const std::string& /*octaveroot*/ = "")
326  { }
327 
328  nested_fcn_handle (const octave_value& fcn, const std::string& name,
329  const std::shared_ptr<stack_frame>& closure_frames);
330 
332 
333  ~nested_fcn_handle (void) = default;
334 
335  nested_fcn_handle * clone (void) const
336  {
337  return new nested_fcn_handle (*this);
338  }
339 
340  std::string type (void) const { return "nested"; }
341 
342  bool is_nested (void) const { return true; }
343 
344  octave_value_list call (int nargout, const octave_value_list& args);
345 
346  // FIXME: These must go away. They don't do the right thing for
347  // scoping or overloads.
349  {
350  return m_fcn.function_value ();
351  }
352 
354  {
355  return m_fcn.user_function_value ();
356  }
357 
358  octave_value fcn_val (void) { return m_fcn; }
359 
360  octave_value workspace (void) const;
361 
362  // Should be const.
363  octave_scalar_map info (void);
364 
365  bool save_ascii (std::ostream& os);
366 
367  bool load_ascii (std::istream& is);
368 
369  bool save_binary (std::ostream& os, bool save_as_floats);
370 
371  bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
372 
373  bool save_hdf5 (octave_hdf5_id loc_id, const char *name, bool save_as_floats);
374 
375  bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
376  octave_hdf5_id& type_hid);
377 
378  void print_raw (std::ostream&, bool pr_as_read_syntax,
379  int current_print_indent_level) const;
380 
381  friend bool is_equal_to (const nested_fcn_handle& fh1,
382  const nested_fcn_handle& fh2);
383 
384  protected:
385 
386  // The function we are handling.
388 
389  // Pointer to closure stack frames.
390  std::shared_ptr<stack_frame> m_closure_frames;
391  };
392 
394  {
395  public:
396 
397  // FIXME: octaveroot is temporary information used when loading
398  // handles. Can we avoid using it in the constructor?
399 
400  class_simple_fcn_handle (const std::string& name,
401  const std::string& file,
402  const std::string& /*octaveroot*/)
404  { }
405 
406  // FIXME: is the method name supposed to be just the method name or
407  // also contain the object name?
408 
409  class_simple_fcn_handle (const std::string& class_nm,
410  const std::string& meth_nm);
411 
413  const std::string& class_nm,
414  const std::string& meth_nm);
415 
416  class_simple_fcn_handle (const octave_value& obj, const octave_value& fcn,
417  const std::string& class_nm,
418  const std::string& meth_nm);
419 
421 
422  ~class_simple_fcn_handle (void) = default;
423 
425  {
426  return new class_simple_fcn_handle (*this);
427  }
428 
429  std::string type (void) const { return "classsimple"; }
430 
431  bool is_class_simple (void) const { return true; }
432 
433  octave_value_list call (int nargout, const octave_value_list& args);
434 
435  // FIXME: These must go away. They don't do the right thing for
436  // scoping or overloads.
438  {
439  // FIXME: Shouldn't the lookup rules here match those used in the
440  // call method?
441 
442  if (m_fcn.is_defined ())
443  return m_fcn.function_value ();
444 
445  symbol_table& symtab
446  = __get_symbol_table__ ("class_simple_fcn_handle::function_value");
447 
448  // FIXME: is caching the correct thing to do?
449  // Cache this value so that the pointer will be valid as long as the
450  // function handle object is valid.
451 
452  // FIXME: This should probably dispatch to the respective class method.
453  // But that breaks if a function handle is used in a class method with
454  // e.g. bsxfun with arguments of a different class (see bug #59661).
455  // m_fcn = symtab.find_method (m_name, m_dispatch_class);
457 
458  return m_fcn.is_defined () ? m_fcn.function_value () : nullptr;
459  }
460 
462  {
463  return m_fcn.user_function_value ();
464  }
465 
466  octave_value fcn_val (void) { return m_fcn; }
467 
468  // Should be const.
469  octave_scalar_map info (void);
470 
471  std::string dispatch_class (void) const { return m_dispatch_class; }
472 
473  bool save_ascii (std::ostream& os);
474 
475  bool load_ascii (std::istream& is);
476 
477  bool save_binary (std::ostream& os, bool save_as_floats);
478 
479  bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
480 
481  bool save_hdf5 (octave_hdf5_id loc_id, const char *name, bool save_as_floats);
482 
483  bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
484  octave_hdf5_id& type_hid);
485 
486  void print_raw (std::ostream&, bool pr_as_read_syntax,
487  int current_print_indent_level) const;
488 
489  friend bool is_equal_to (const class_simple_fcn_handle& fh1,
490  const class_simple_fcn_handle& fh2);
491 
492  protected:
493 
494  // The object containing the method we are handing.
496 
497  // The method we are handling.
499 
500  // Name of the class that m_fcn belongs to.
501  std::string m_dispatch_class;
502  };
503 
505  {
506  public:
507 
508  static const std::string anonymous;
509 
510  // Setting NAME here is a bit of a kluge to cope with a bad choice
511  // made to append the number of local variables to the @<anonymous>
512  // tag in the binary file format. See also the save_binary and
513  // load_binary functions.
514 
515  anonymous_fcn_handle (const std::string& name = "")
517  { }
518 
520  const stack_frame::local_vars_map& local_vars);
521 
523 
524  ~anonymous_fcn_handle (void) = default;
525 
527  {
528  return new anonymous_fcn_handle (*this);
529  }
530 
531  std::string type (void) const { return "anonymous"; }
532 
533  bool is_anonymous (void) const { return true; }
534 
535  octave_value_list call (int nargout, const octave_value_list& args);
536 
537  // FIXME: These must go away. They don't do the right thing for
538  // scoping or overloads.
540  {
541  return m_fcn.function_value ();
542  }
543 
545  {
546  return m_fcn.user_function_value ();
547  }
548 
549  octave_value fcn_val (void) { return m_fcn; }
550 
551  octave_value workspace (void) const;
552 
553  // Should be const.
554  octave_scalar_map info (void);
555 
556  bool save_ascii (std::ostream& os);
557 
558  bool load_ascii (std::istream& is);
559 
560  bool save_binary (std::ostream& os, bool save_as_floats);
561 
562  bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
563 
564  bool save_hdf5 (octave_hdf5_id loc_id, const char *name, bool save_as_floats);
565 
566  bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
567  octave_hdf5_id& type_hid);
568 
569  void print_raw (std::ostream&, bool pr_as_read_syntax,
570  int current_print_indent_level) const;
571 
572  // Anonymous function handles are printed without a newline.
573  bool print_as_scalar (void) const { return false; }
574 
575  bool parse (const std::string& fcn_text);
576 
577  friend bool is_equal_to (const anonymous_fcn_handle& fh1,
578  const anonymous_fcn_handle& fh2);
579 
580  protected:
581 
582  // The function we are handling.
584 
585  // List of captured variable values for anonymous fucntions.
587  };
588 
589  const std::string anonymous_fcn_handle::anonymous ("@<anonymous>");
590 
591  extern bool is_equal_to (const anonymous_fcn_handle& fh1,
592  const anonymous_fcn_handle& fh2);
593 
594  static void err_invalid_fcn_handle (const std::string& name)
595  {
596  error ("invalid function handle, unable to find function for @%s",
597  name.c_str ());
598  }
599 
601  base_fcn_handle::subsref (const std::string& type,
602  const std::list<octave_value_list>& idx,
603  int nargout)
604  {
606 
607  switch (type[0])
608  {
609  case '(':
610  {
611  int tmp_nargout = (type.length () > 1 && nargout == 0) ? 1 : nargout;
612 
613  retval = call (tmp_nargout, idx.front ());
614  }
615  break;
616 
617  case '{':
618  case '.':
619  error ("function handle cannot be indexed with %c", type[0]);
620  break;
621 
622  default:
623  panic_impossible ();
624  }
625 
626  // FIXME: perhaps there should be an
627  // octave_value_list::next_subsref member function? See also
628  // octave_builtin::subsref.
629 
630  if (idx.size () > 1)
631  retval = retval(0).next_subsref (nargout, type, idx);
632 
633  return retval;
634  }
635 
638  {
639  std::ostringstream buf;
640  print_raw (buf, true, 0);
641  return octave_value (buf.str (), type);
642  }
643 
644  bool
646  {
647  unimplemented ("save", "text");
648 
649  return true;
650  }
651 
652  bool
654  {
655  unimplemented ("load", "text");
656 
657  return true;
658  }
659 
660  bool
661  base_fcn_handle::save_binary (std::ostream&, bool)
662  {
663  unimplemented ("save", "binary");
664 
665  return true;
666  }
667 
668  bool
670  {
671  unimplemented ("load", "binary");
672 
673  return true;
674  }
675 
676  bool
678  {
679  unimplemented ("save", "hdf5");
680 
681  return true;
682  }
683 
684  bool
686  {
687  unimplemented ("load", "hdf5");
688 
689  return true;
690  }
691 
692  void base_fcn_handle::warn_load (const char *file_type) const
693  {
694  std::string obj_type = type ();
695 
697  ("Octave:load-save-unavailable",
698  "%s: loading %s files not available in this version of Octave",
699  obj_type.c_str (), file_type);
700  }
701 
702  void base_fcn_handle::warn_save (const char *file_type) const
703  {
704  std::string obj_type = type ();
705 
707  ("Octave:load-save-unavailable",
708  "%s: saving %s files not available in this version of Octave",
709  obj_type.c_str (), file_type);
710  }
711 
712  void base_fcn_handle::unimplemented (const char *op, const char *fmt) const
713  {
714  std::string htype = type ();
715 
716  warning ("%s for %s handles with %s format is not implemented",
717  op, htype.c_str (), fmt);
718  }
719 
722  {
723  error ("invalid call to invalid function handle");
724  }
725 
727  internal_fcn_handle::call (int nargout, const octave_value_list& args)
728  {
729  interpreter& interp = __get_interpreter__ ("internal_fcn_handle::call");
730 
731  return interp.feval (m_fcn, args, nargout);
732  }
733 
735  {
737 
738  m.setfield ("function", fcn_name ());
739  m.setfield ("type", type ());
740  m.setfield ("file", "");
741 
742  return m;
743  }
744 
746  const internal_fcn_handle& fh2)
747  {
748  if (fh1.m_name == fh2.m_name
749  && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
750  return fh1.m_fcn.is_copy_of (fh2.m_fcn);
751  else
752  return false;
753  }
754 
756  simple_fcn_handle::call (int nargout, const octave_value_list& args)
757  {
758  // FIXME: if m_name has a '.' in the name, lookup first component. If
759  // it is a classdef meta object, then build TYPE and IDX arguments and
760  // make a subsref call using them.
761 
762  interpreter& interp = __get_interpreter__ ("simple_fcn_handle::call");
763 
764  octave_value fcn_to_call;
765 
766  // The following code is similar to part of
767  // tree_evaluator::visit_index_expression but simpler because it
768  // handles a more restricted case.
769 
770  symbol_table& symtab = interp.get_symbol_table ();
771 
772  size_t pos = m_name.find ('.');
773 
774  if (pos != std::string::npos)
775  {
776  // FIXME: check to see which of these cases actually work in
777  // Octave and Matlab. For the last two, assume handle is
778  // created before object is defined as an object.
779  //
780  // We can have one of
781  //
782  // pkg-list . fcn (args)
783  // pkg-list . cls . meth (args)
784  // class-name . method (args)
785  // class-name . static-method (args)
786  // object . method (args)
787  // object . static-method (args)
788 
789  // Evaluate package elements until we find a function,
790  // classdef object, or classdef_meta object that is not a
791  // package. An object may only appear as the first element,
792  // then it must be followed directly by a function name.
793 
794  size_t beg = 0;
795  size_t end = pos;
796 
797  std::vector<std::string> idx_elts;
798 
799  while (true)
800  {
801  end = m_name.find ('.', beg);
802 
803  idx_elts.push_back (m_name.substr (beg, end-beg));
804 
805  if (end == std::string::npos)
806  break;
807 
808  beg = end+1;
809  }
810 
811  size_t n_elts = idx_elts.size ();
812 
813  bool have_object = false;
814  octave_value partial_expr_val;
815 
816  // Lazy evaluation. The first element was not known to be defined
817  // as an object in the scope where the handle was created. See if
818  // there is a definition in the current scope.
819 
820  partial_expr_val = interp.varval (idx_elts[0]);
821 
822  if (partial_expr_val.is_defined ())
823  {
824  if (! partial_expr_val.is_classdef_object () || n_elts != 2)
826 
827  have_object = true;
828  }
829  else
830  partial_expr_val = symtab.find_function (idx_elts[0], ovl ());
831 
832  std::string type;
833  std::list<octave_value_list> arg_list;
834 
835  for (size_t i = 1; i < n_elts; i++)
836  {
837  if (partial_expr_val.is_package ())
838  {
839  if (have_object)
841 
842  type = ".";
843  arg_list.push_back (ovl (idx_elts[i]));
844 
845  try
846  {
847  // Silently ignore extra output values.
848 
849  octave_value_list tmp_list
850  = partial_expr_val.subsref (type, arg_list, 0);
851 
852  partial_expr_val
853  = tmp_list.length () ? tmp_list(0) : octave_value ();
854 
855  if (partial_expr_val.is_cs_list ())
857 
858  arg_list.clear ();
859  }
860  catch (index_exception&)
861  {
863  }
864  }
865  else if (have_object || partial_expr_val.is_classdef_meta ())
866  {
867  // Object or class name must be the next to the last
868  // element (it was the previous one, so if this is the
869  // final element, it should be a classdef method,
870  // but we'll let the classdef or classdef_meta subsref
871  // function sort that out.
872 
873  if (i != n_elts-1)
875 
876  type = ".(";
877  arg_list.push_back (ovl (idx_elts[i]));
878  arg_list.push_back (args);
879 
880  return partial_expr_val.subsref (type, arg_list, nargout);
881  }
882  else
884  }
885 
886  // If we get here, we must have a function to call.
887 
888  if (! partial_expr_val.is_function ())
890 
891  fcn_to_call = partial_expr_val;
892  }
893  else
894  {
895  // No "." in the name.
896 
897  // Perform function lookup given current arguments. We'll need
898  // to do this regardless of whether a function was found when
899  // the handle was created.
900 
901  octave_value ov_fcn = symtab.find_function (m_name, args);
902 
903  if (m_fcn.is_defined ())
904  {
905  // A simple function was found when the handle was created.
906  // Use that unless we find a class method to override it.
907 
908  fcn_to_call = m_fcn;
909 
910  if (ov_fcn.is_defined ())
911  {
912  octave_function *fcn = ov_fcn.function_value ();
913 
914  std::string dispatch_class = fcn->dispatch_class ();
915 
916  if (fcn->is_class_method ())
917  {
918  // Function found through lookup is a class method
919  // so use it instead of the simple one found when
920  // the handle was created.
921 
922  fcn_to_call = ov_fcn;
923  }
924  }
925  }
926  else
927  {
928  // There was no simple function found when the handle was
929  // created so use the one found here (if any).
930 
931  fcn_to_call = ov_fcn;
932  }
933  }
934 
935  if (! fcn_to_call.is_defined ())
937 
938  return interp.feval (fcn_to_call, args, nargout);
939  }
940 
942  {
943  // FIXME: Shouldn't the lookup rules here match those used in the
944  // call method?
945 
946  if (m_fcn.is_defined ())
947  return m_fcn.function_value ();
948 
949  symbol_table& symtab
950  = __get_symbol_table__ ("simple_fcn_handle::function_value");
951 
952  // FIXME: is caching the correct thing to do?
953  // Cache this value so that the pointer will be valid as long as the
954  // function handle object is valid.
955 
957 
958  return m_fcn.is_defined () ? m_fcn.function_value () : nullptr;
959  }
960 
962  {
963  // FIXME: Shouldn't the lookup rules here match those used in the
964  // call method?
965 
966  if (m_fcn.is_defined ())
967  return m_fcn.user_function_value ();
968 
969  symbol_table& symtab
970  = __get_symbol_table__ ("simple_fcn_handle::user_function_value");
971 
972  // FIXME: is caching the correct thing to do?
973  // Cache this value so that the pointer will be valid as long as the
974  // function handle object is valid.
975 
976  m_fcn = symtab.find_user_function (m_name);
977 
978  return m_fcn.is_defined () ? m_fcn.user_function_value () : nullptr;
979  }
980 
982  {
983  if (m_fcn.is_defined ())
984  return m_fcn;
985 
986  symbol_table& symtab
987  = __get_symbol_table__ ("simple_fcn_handle::user_function_value");
988 
989  // FIXME: is caching the correct thing to do?
990  // Cache this value so that the pointer will be valid as long as the
991  // function handle object is valid.
992 
993  m_fcn = symtab.find_user_function (m_name);
994 
995  return m_fcn;
996  }
997 
999  {
1001 
1002  m.setfield ("function", fcn_name ());
1003  m.setfield ("type", type ());
1004  // When is FILE defined for simple function handles?
1005  m.setfield ("file", file ());
1006 
1007  return m;
1008  }
1009 
1010  bool simple_fcn_handle::save_ascii (std::ostream& os)
1011  {
1012  os << "# octaveroot: " << config::octave_exec_home () << "\n";
1013 
1014  std::string fnm = file ();
1015  if (! fnm.empty ())
1016  os << "# path: " << fnm << "\n";
1017 
1018  os << "# subtype: " << type () << "\n";
1019 
1020  os << m_name << "\n";
1021 
1022  return true;
1023  }
1024 
1025  bool simple_fcn_handle::load_ascii (std::istream& is)
1026  {
1027  // FIXME: If m_file is not empty, try to load the file and define
1028  // the function? Is it an error if that fails? Or should this job
1029  // always be deferred until the handle is used?
1030 
1031  return is.good ();
1032  }
1033 
1034  bool simple_fcn_handle::save_binary (std::ostream& os, bool)
1035  {
1036  std::ostringstream nmbuf;
1037 
1038  // When is FILE defined for simple function handles?
1039  std::string fnm;
1040 
1041  nmbuf << m_name << "@<simple>\n" << config::octave_exec_home ()
1042  << "\n" << fnm;
1043 
1044  std::string buf_str = nmbuf.str ();
1045  int32_t tmp = buf_str.length ();
1046  os.write (reinterpret_cast<char *> (&tmp), 4);
1047  os.write (buf_str.c_str (), buf_str.length ());
1048 
1049  return true;
1050  }
1051 
1052  bool simple_fcn_handle::load_binary (std::istream& is, bool,
1054  {
1055  return is.good ();
1056  }
1057 
1059  bool)
1060  {
1061 #if defined (HAVE_HDF5)
1062 
1063  bool retval = true;
1064 
1065  octave_hdf5_id group_hid = -1;
1066 #if defined (HAVE_HDF5_18)
1067  group_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT,
1069 #else
1070  group_hid = H5Gcreate (loc_id, name, 0);
1071 #endif
1072  if (group_hid < 0)
1073  return false;
1074 
1075  octave_hdf5_id space_hid, data_hid, type_hid;
1076  space_hid = data_hid = type_hid = -1;
1077 
1078  // attach the type of the variable
1079  type_hid = H5Tcopy (H5T_C_S1);
1080  H5Tset_size (type_hid, m_name.length () + 1);
1081  if (type_hid < 0)
1082  {
1083  H5Gclose (group_hid);
1084  return false;
1085  }
1086 
1087  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2);
1088  hdims[0] = 0;
1089  hdims[1] = 0;
1090  space_hid = H5Screate_simple (0, hdims, nullptr);
1091  if (space_hid < 0)
1092  {
1093  H5Tclose (type_hid);
1094  H5Gclose (group_hid);
1095  return false;
1096  }
1097 #if defined (HAVE_HDF5_18)
1098  data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid,
1101 #else
1102  data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid,
1104 #endif
1105  if (data_hid < 0
1106  || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
1107  octave_H5P_DEFAULT, m_name.c_str ()) < 0)
1108  {
1109  H5Sclose (space_hid);
1110  H5Tclose (type_hid);
1111  H5Gclose (group_hid);
1112  return false;
1113  }
1114  H5Dclose (data_hid);
1115 
1116  std::string octaveroot = config::octave_exec_home ();
1117 
1118  // When is FILE defined for simple fucntion handles?
1119  std::string fpath;
1120 
1121  H5Sclose (space_hid);
1122  hdims[0] = 1;
1123  hdims[1] = octaveroot.length ();
1124  space_hid = H5Screate_simple (0, hdims, nullptr);
1125  if (space_hid < 0)
1126  {
1127  H5Tclose (type_hid);
1128  H5Gclose (group_hid);
1129  return false;
1130  }
1131 
1132  H5Tclose (type_hid);
1133  type_hid = H5Tcopy (H5T_C_S1);
1134  H5Tset_size (type_hid, octaveroot.length () + 1);
1135  octave_hdf5_id a_id;
1136 #if defined (HAVE_HDF5_18)
1137  a_id = H5Acreate (group_hid, "OCTAVEROOT", type_hid, space_hid,
1139 #else
1140  a_id = H5Acreate (group_hid, "OCTAVEROOT", type_hid, space_hid,
1142 #endif
1143 
1144  if (a_id >= 0)
1145  {
1146  retval = (H5Awrite (a_id, type_hid, octaveroot.c_str ()) >= 0);
1147 
1148  H5Aclose (a_id);
1149  }
1150  else
1151  {
1152  H5Sclose (space_hid);
1153  H5Tclose (type_hid);
1154  H5Gclose (group_hid);
1155  return false;
1156  }
1157 
1158  H5Sclose (space_hid);
1159  hdims[0] = 1;
1160  hdims[1] = fpath.length ();
1161  space_hid = H5Screate_simple (0, hdims, nullptr);
1162  if (space_hid < 0)
1163  {
1164  H5Tclose (type_hid);
1165  H5Gclose (group_hid);
1166  return false;
1167  }
1168 
1169  H5Tclose (type_hid);
1170  type_hid = H5Tcopy (H5T_C_S1);
1171  H5Tset_size (type_hid, fpath.length () + 1);
1172 
1173 #if defined (HAVE_HDF5_18)
1174  a_id = H5Acreate (group_hid, "FILE", type_hid, space_hid,
1176 #else
1177  a_id = H5Acreate (group_hid, "FILE", type_hid, space_hid, octave_H5P_DEFAULT);
1178 #endif
1179 
1180  if (a_id >= 0)
1181  {
1182  retval = (H5Awrite (a_id, type_hid, fpath.c_str ()) >= 0);
1183 
1184  H5Aclose (a_id);
1185  }
1186  else
1187  retval = false;
1188 
1189  H5Sclose (space_hid);
1190  H5Tclose (type_hid);
1191  H5Gclose (group_hid);
1192 
1193  return retval;
1194 
1195 #else
1196 
1197  octave_unused_parameter (loc_id);
1198  octave_unused_parameter (name);
1199 
1200  warn_save ("hdf5");
1201 
1202  return false;
1203 
1204 #endif
1205  }
1206 
1208  octave_hdf5_id& space_hid,
1209  octave_hdf5_id& type_hid)
1210  {
1211 #if defined (HAVE_HDF5)
1212 
1213  unimplemented ("load", "hdf5");
1214 
1215  octave_unused_parameter (group_hid);
1216  octave_unused_parameter (space_hid);
1217  octave_unused_parameter (type_hid);
1218 
1219  return true;
1220 
1221 #else
1222 
1223  octave_unused_parameter (group_hid);
1224  octave_unused_parameter (space_hid);
1225  octave_unused_parameter (type_hid);
1226 
1227  return false;
1228 
1229 #endif
1230  }
1231 
1232  void simple_fcn_handle::print_raw (std::ostream& os, bool pr_as_read_syntax,
1233  int current_print_indent_level) const
1234  {
1235  octave_print_internal (os, '@' + m_name, pr_as_read_syntax,
1236  current_print_indent_level);
1237  }
1238 
1239  bool is_equal_to (const simple_fcn_handle& fh1, const simple_fcn_handle& fh2)
1240  {
1241  if (fh1.m_name == fh2.m_name)
1242  {
1243  if (fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
1244  return fh1.m_fcn.is_copy_of (fh2.m_fcn);
1245 
1246  if (fh1.m_fcn.is_undefined () && fh2.m_fcn.is_undefined ())
1247  return true;
1248  }
1249 
1250  return false;
1251  }
1252 
1254  const std::string& name,
1255  const std::list<std::string>& parentage)
1256  : base_fcn_handle (name), m_fcn (fcn), m_parentage (parentage)
1257  {
1258  // FIXME: should it be an error if FCN is undefined?
1259 
1260  if (m_fcn.is_defined ())
1261  {
1262  octave_function *oct_fcn = m_fcn.function_value ();
1263 
1264  if (oct_fcn)
1265  m_file = oct_fcn->fcn_file_name ();
1266  }
1267 
1268  m_parentage.push_front (name);
1269  }
1270 
1272  scoped_fcn_handle::call (int nargout, const octave_value_list& args)
1273  {
1274  // FIXME: we aren't really using the scope yet. Hmm.
1275 
1276  interpreter& interp = __get_interpreter__ ("simple_fcn_handle::call");
1277 
1278  if (! m_fcn.is_defined ())
1279  {
1280  // Try to find it?
1281 
1282  find_function ();
1283  }
1284 
1285  if (! m_fcn.is_defined ())
1287 
1288  return interp.feval (m_fcn, args, nargout);
1289  }
1290 
1292  {
1294 
1295  m.setfield ("function", fcn_name ());
1296  m.setfield ("type", type ());
1297  m.setfield ("file", file ());
1298 
1299  m.setfield ("parentage", Cell (m_parentage));
1300 
1301  return m;
1302  }
1303 
1304  bool scoped_fcn_handle::save_ascii (std::ostream& os)
1305  {
1306  os << "# octaveroot: " << config::octave_exec_home () << "\n";
1307 
1308  std::string fnm = file ();
1309  if (! fnm.empty ())
1310  os << "# path: " << fnm << "\n";
1311 
1312  os << "# subtype: " << type () << "\n";
1313 
1314  os << m_name << "\n";
1315 
1316  octave_value tmp = Cell (m_parentage);
1317  tmp.save_ascii (os);
1318 
1319  return os.good ();
1320  }
1321 
1322  bool scoped_fcn_handle::load_ascii (std::istream& is)
1323  {
1324  octave_cell ov_cell;
1325  ov_cell.load_ascii (is);
1326 
1327  if (ov_cell.iscellstr ())
1328  {
1329  Array<std::string> cellstr_val = ov_cell.cellstr_value ();
1330 
1331  for (octave_idx_type i = 0; i < cellstr_val.numel (); i++)
1332  m_parentage.push_back (cellstr_val(i));
1333  }
1334 
1335  return is.good ();
1336  }
1337 
1338  bool scoped_fcn_handle::save_binary (std::ostream& os, bool save_as_floats)
1339  {
1340  std::ostringstream nmbuf;
1341 
1342  std::string fnm = file ();
1343 
1344  nmbuf << m_name << "@<scopedfunction>\n" << config::octave_exec_home ()
1345  << "\n" << fnm;
1346 
1347  std::string buf_str = nmbuf.str ();
1348  int32_t len = buf_str.length ();
1349  os.write (reinterpret_cast<char *> (&len), 4);
1350  os.write (buf_str.c_str (), buf_str.length ());
1351 
1352  octave_value tmp = Cell (m_parentage);
1353  tmp.save_binary (os, save_as_floats);
1354 
1355  return os.good ();
1356  }
1357 
1358  bool scoped_fcn_handle::load_binary (std::istream& is, bool swap,
1360  {
1361  octave_cell ov_cell;
1362  ov_cell.load_binary (is, swap, fmt);
1363 
1364  if (ov_cell.iscellstr ())
1365  {
1366  Array<std::string> cellstr_val = ov_cell.cellstr_value ();
1367 
1368  for (octave_idx_type i = 0; i < cellstr_val.numel (); i++)
1369  m_parentage.push_back (cellstr_val(i));
1370  }
1371 
1372  return is.good ();
1373  }
1374 
1376  bool)
1377  {
1378 #if defined (HAVE_HDF5)
1379 
1380  unimplemented ("save", "hdf5");
1381 
1382  // FIXME: save parentage.
1383 
1384  octave_unused_parameter (loc_id);
1385  octave_unused_parameter (name);
1386 
1387  return true;
1388 
1389 #else
1390 
1391  octave_unused_parameter (loc_id);
1392  octave_unused_parameter (name);
1393 
1394  warn_save ("hdf5");
1395 
1396  return false;
1397 
1398 #endif
1399  }
1400 
1402  octave_hdf5_id& space_hid,
1403  octave_hdf5_id& type_hid)
1404  {
1405 #if defined (HAVE_HDF5)
1406 
1407  unimplemented ("load", "hdf5");
1408 
1409  // FIXME: load parentage.
1410 
1411  octave_unused_parameter (group_hid);
1412  octave_unused_parameter (space_hid);
1413  octave_unused_parameter (type_hid);
1414 
1415  return true;
1416 
1417 #else
1418 
1419  octave_unused_parameter (group_hid);
1420  octave_unused_parameter (space_hid);
1421  octave_unused_parameter (type_hid);
1422 
1423  return false;
1424 
1425 #endif
1426  }
1427 
1428  void scoped_fcn_handle::print_raw (std::ostream& os,
1429  bool pr_as_read_syntax,
1430  int current_print_indent_level) const
1431  {
1432  octave_print_internal (os, '@' + m_name, pr_as_read_syntax,
1433  current_print_indent_level);
1434  }
1435 
1436  bool is_equal_to (const scoped_fcn_handle& fh1, const scoped_fcn_handle& fh2)
1437  {
1438  if (fh1.m_name == fh2.m_name
1439  && fh2.m_parentage == fh2.m_parentage
1440  && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
1441  return fh1.m_fcn.is_copy_of (fh2.m_fcn);
1442  else
1443  return false;
1444  }
1445 
1447  {
1448  // Since a scoped function is not visible by itself, try to load the
1449  // file named in m_file then find and define the scoped function.
1450  // It is not an error if this fails. We can report later that the
1451  // handle is invalid.
1452 
1453  symbol_table& symtab
1454  = __get_symbol_table__ ("scoped_fcn_handle::find_function");
1455 
1456  if (m_parentage.size () == 1)
1457  {
1458  std::string dir_name = sys::file_ops::dirname (m_file);
1459 
1460  size_t pos = dir_name.find_last_of (sys::file_ops::dir_sep_chars ());
1461 
1462  if (pos != std::string::npos)
1463  dir_name = dir_name.substr (0, pos);
1464  else if (dir_name == "private")
1465  dir_name = ".";
1466 
1467  std::string fcn_name = m_parentage.front ();
1468 
1469  // FIXME: Does dir_name need to be in the load path for this to work?
1470 
1471  m_fcn = symtab.find_private_function (dir_name, m_name);
1472 
1473  // FIXME: Verify that it is a private function?
1474  }
1475  else
1476  {
1477  std::string primary_parent_name = m_parentage.back ();
1478 
1479  octave_value ov_parent_fcn
1480  = symtab.find_user_function (primary_parent_name);
1481 
1482  if (ov_parent_fcn.is_defined ())
1483  {
1484  octave_user_function *fcn = ov_parent_fcn.user_function_value ();
1485 
1486  if (fcn)
1487  {
1488  std::string file_name = fcn->fcn_file_name ();
1489 
1490  std::string oct_home = config::octave_exec_home ();
1491 
1492  if (file_name.substr (0, oct_home.size ()) == oct_home)
1493  file_name = file_name.substr (oct_home.size ());
1494 
1495  octave_value subfun = fcn->find_subfunction (m_name);
1496 
1497  if (subfun.is_defined ())
1498  m_fcn = subfun;
1499  }
1500  }
1501  }
1502  }
1503 
1505  const std::string& name,
1506  const std::shared_ptr<stack_frame>& closure_frames)
1507  : base_fcn_handle (name), m_fcn (fcn), m_closure_frames (closure_frames)
1508  { }
1509 
1511  nested_fcn_handle::call (int nargout, const octave_value_list& args)
1512  {
1513  tree_evaluator& tw = __get_evaluator__ ("nested_fcn_handle::call");
1514 
1516 
1517  tw.push_stack_frame (oct_usr_fcn, m_closure_frames);
1518 
1519  unwind_action act ([&tw] () { tw.pop_stack_frame (); });
1520 
1521  return oct_usr_fcn->execute (tw, nargout, args);
1522  }
1523 
1525  {
1526  return m_closure_frames->workspace ();
1527  }
1528 
1530  {
1532 
1533  m.setfield ("function", fcn_name ());
1534  m.setfield ("type", type ());
1535  m.setfield ("file", "");
1536  m.setfield ("workspace", workspace ());
1537 
1538  return m;
1539  }
1540 
1541  // FIXME: For save, we need a way to save the (possibly shared)
1542  // workspace. For load, we need a way to load and link to the
1543  // (possibly shared) workspace that was saved.
1544  //
1545  // Since a nested function is not visible by itself, do we need to try
1546  // to load the file named in m_file then find and define the function?
1547  // Is it an error if that fails? Or should this job always be
1548  // deferred until the handle is used?
1549 
1550  bool nested_fcn_handle::save_ascii (std::ostream& os)
1551  {
1552  unimplemented ("save", "text");
1553 
1554  octave_unused_parameter (os);
1555 
1556  return true;
1557  }
1558 
1559  bool nested_fcn_handle::load_ascii (std::istream& is)
1560  {
1561  unimplemented ("load", "text");
1562 
1563  octave_unused_parameter (is);
1564 
1565  return true;
1566  }
1567 
1568  bool nested_fcn_handle::save_binary (std::ostream& os, bool save_as_floats)
1569  {
1570  unimplemented ("save", "binary");
1571 
1572  octave_unused_parameter (os);
1573  octave_unused_parameter (save_as_floats);
1574 
1575  return true;
1576  }
1577 
1578  bool nested_fcn_handle::load_binary (std::istream& is, bool swap,
1580  {
1581  unimplemented ("load", "binary");
1582 
1583  octave_unused_parameter (is);
1584  octave_unused_parameter (swap);
1585  octave_unused_parameter (fmt);
1586 
1587  return true;
1588  }
1589 
1591  bool)
1592  {
1593 #if defined (HAVE_HDF5)
1594 
1595  unimplemented ("save", "hdf5");
1596 
1597  octave_unused_parameter (loc_id);
1598  octave_unused_parameter (name);
1599 
1600  return true;
1601 
1602 #else
1603 
1604  octave_unused_parameter (loc_id);
1605  octave_unused_parameter (name);
1606 
1607  warn_save ("hdf5");
1608 
1609  return false;
1610 
1611 #endif
1612  }
1613 
1615  octave_hdf5_id& space_hid,
1616  octave_hdf5_id& type_hid)
1617  {
1618 #if defined (HAVE_HDF5)
1619 
1620  unimplemented ("load", "hdf5");
1621 
1622  octave_unused_parameter (group_hid);
1623  octave_unused_parameter (space_hid);
1624  octave_unused_parameter (type_hid);
1625 
1626  return true;
1627 
1628 #else
1629 
1630  octave_unused_parameter (group_hid);
1631  octave_unused_parameter (space_hid);
1632  octave_unused_parameter (type_hid);
1633 
1634  return false;
1635 
1636 #endif
1637  }
1638 
1639  void nested_fcn_handle::print_raw (std::ostream& os,
1640  bool pr_as_read_syntax,
1641  int current_print_indent_level) const
1642  {
1643  octave_print_internal (os, '@' + m_name, pr_as_read_syntax,
1644  current_print_indent_level);
1645  }
1646 
1647  bool is_equal_to (const nested_fcn_handle& fh1, const nested_fcn_handle& fh2)
1648  {
1649  if (fh1.m_name == fh2.m_name
1650  && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
1651  return fh1.m_fcn.is_copy_of (fh2.m_fcn);
1652  else
1653  return false;
1654  }
1655 
1657  const std::string& meth_nm)
1658  : base_fcn_handle (meth_nm), m_obj (), m_fcn (),
1659  m_dispatch_class (class_nm)
1660  { }
1661 
1663  const std::string& class_nm,
1664  const std::string& meth_nm)
1665  : base_fcn_handle (meth_nm), m_obj (), m_fcn (fcn),
1666  m_dispatch_class (class_nm)
1667  { }
1668 
1670  const octave_value& fcn,
1671  const std::string& class_nm,
1672  const std::string& meth_nm)
1673  : base_fcn_handle (meth_nm), m_obj (obj), m_fcn (fcn),
1674  m_dispatch_class (class_nm)
1675  { }
1676 
1679  {
1680  interpreter& interp = __get_interpreter__ ("class_simple_fcn_handle::call");
1681 
1682  if (m_obj.is_defined ())
1683  {
1684  octave_value_list tmp_args = args;
1685  tmp_args.prepend (m_obj);
1686 
1687  return interp.feval (m_fcn, tmp_args, nargout);
1688  }
1689 
1690  // FIXME: is this the best approach? Should we be saving current
1691  // dispatch class and restoring that value instead of
1692  // unconditionally setting it to "" when we return from this
1693  // function?
1694 
1695  tree_evaluator& tw = interp.get_evaluator ();
1696 
1697  unwind_action act ([&tw] () { tw.set_dispatch_class (""); });
1698 
1700 
1701  if (m_fcn.is_defined ())
1702  return interp.feval (m_fcn, args, nargout);
1703 
1704  return interp.feval (fcn_name (), args, nargout);
1705  }
1706 
1708  {
1710 
1711  m.setfield ("function", fcn_name ());
1712  m.setfield ("type", type ());
1713  m.setfield ("file", "");
1714  m.setfield ("class", dispatch_class ());
1715 
1716  return m;
1717  }
1718 
1719  // FIXME: Since a class method is not visible by itself, do we need to
1720  // try to load the file named in m_file then find and define the
1721  // function? Is it an error if that fails? Or should this job always
1722  // be deferred until the handle is used?
1723 
1724  bool class_simple_fcn_handle::save_ascii (std::ostream& os)
1725  {
1726  unimplemented ("save", "text");
1727 
1728  octave_unused_parameter (os);
1729 
1730  return true;
1731  }
1732 
1733  bool class_simple_fcn_handle::load_ascii (std::istream& is)
1734  {
1735  unimplemented ("load", "text");
1736 
1737  octave_unused_parameter (is);
1738 
1739  return true;
1740  }
1741 
1743  bool save_as_floats)
1744  {
1745  unimplemented ("save", "binary");
1746 
1747  octave_unused_parameter (os);
1748  octave_unused_parameter (save_as_floats);
1749 
1750  return true;
1751  }
1752 
1753  bool class_simple_fcn_handle::load_binary (std::istream& is, bool swap,
1755  {
1756  unimplemented ("load", "binary");
1757 
1758  octave_unused_parameter (is);
1759  octave_unused_parameter (swap);
1760  octave_unused_parameter (fmt);
1761 
1762  return true;
1763  }
1764 
1766  const char *name, bool)
1767  {
1768 #if defined (HAVE_HDF5)
1769 
1770  unimplemented ("save", "hdf5");
1771 
1772  octave_unused_parameter (loc_id);
1773  octave_unused_parameter (name);
1774 
1775  return true;
1776 
1777 #else
1778 
1779  octave_unused_parameter (loc_id);
1780  octave_unused_parameter (name);
1781 
1782  warn_save ("hdf5");
1783 
1784  return false;
1785 
1786 #endif
1787  }
1788 
1790  octave_hdf5_id& space_hid,
1791  octave_hdf5_id& type_hid)
1792  {
1793 #if defined (HAVE_HDF5)
1794 
1795  unimplemented ("load", "hdf5");
1796 
1797  octave_unused_parameter (group_hid);
1798  octave_unused_parameter (space_hid);
1799  octave_unused_parameter (type_hid);
1800 
1801  return true;
1802 
1803 #else
1804 
1805  octave_unused_parameter (group_hid);
1806  octave_unused_parameter (space_hid);
1807  octave_unused_parameter (type_hid);
1808 
1809  return false;
1810 
1811 #endif
1812  }
1813 
1814  void class_simple_fcn_handle::print_raw (std::ostream& os,
1815  bool pr_as_read_syntax,
1816  int current_print_indent_level) const
1817  {
1818  octave_print_internal (os, '@' + m_name, pr_as_read_syntax,
1819  current_print_indent_level);
1820  }
1821 
1823  const class_simple_fcn_handle& fh2)
1824  {
1825  // FIXME: Also need to check object values are equivalent?
1826 
1827  if (fh1.m_name == fh2.m_name
1828  && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
1829  return fh1.m_fcn.is_copy_of (fh2.m_fcn);
1830  else
1831  return false;
1832  }
1833 
1835  const stack_frame::local_vars_map& local_vars)
1836  : base_fcn_handle (anonymous), m_fcn (fcn), m_local_vars (local_vars)
1837  { }
1838 
1841  {
1842  tree_evaluator& tw = __get_evaluator__ ("anonymous_fcn_handle::call");
1843 
1845 
1846  tw.push_stack_frame (oct_usr_fcn, m_local_vars);
1847 
1848  unwind_action act ([&tw] () { tw.pop_stack_frame (); });
1849 
1850  return oct_usr_fcn->execute (tw, nargout, args);
1851  }
1852 
1854  {
1855  octave_scalar_map ws;
1856 
1857  for (const auto& nm_val : m_local_vars)
1858  ws.assign (nm_val.first, nm_val.second);
1859 
1860  return ws;
1861  }
1862 
1864  {
1866 
1867  std::ostringstream buf;
1868  print_raw (buf, true, 0);
1869  m.setfield ("function", buf.str ());
1870 
1871  m.setfield ("type", type ());
1872  m.setfield ("file", "");
1873  m.setfield ("workspace", Cell (workspace ()));
1874  m.setfield ("within_file_path", "");
1875 
1876  return m;
1877  }
1878 
1879  bool anonymous_fcn_handle::save_ascii (std::ostream& os)
1880  {
1881  // FIXME: can we ensure that m_fcn is always defined?
1882 
1883  if (m_fcn.is_undefined ())
1884  return false;
1885 
1886  os << m_name << "\n";
1887 
1888  print_raw (os, true, 0);
1889  os << "\n";
1890 
1891  size_t varlen = m_local_vars.size ();
1892 
1893  if (varlen > 0)
1894  {
1895  os << "# length: " << varlen << "\n";
1896 
1897  for (const auto& nm_val : m_local_vars)
1898  {
1899  if (! save_text_data (os, nm_val.second, nm_val.first, false, 0))
1900  return ! os.fail ();
1901  }
1902  }
1903 
1904  return true;
1905  }
1906 
1907  bool anonymous_fcn_handle::load_ascii (std::istream& is)
1908  {
1910 
1911  std::string buf;
1912 
1913  if (is)
1914  {
1915  // Get a line of text whitespace characters included, leaving
1916  // newline in the stream.
1917 
1918  buf = read_until_newline (is, true);
1919  }
1920 
1921  std::streampos pos = is.tellg ();
1922 
1923  unwind_protect_safe frame;
1924 
1925  // Set up temporary scope to use for evaluating the text that
1926  // defines the anonymous function.
1927 
1928  interpreter& interp
1929  = __get_interpreter__ ("anonymous_fcn_handle::load_ascii");
1930 
1931  tree_evaluator& tw = interp.get_evaluator ();
1932 
1933  tw.push_dummy_scope (buf);
1935 
1936  octave_idx_type len = 0;
1937 
1938  if (extract_keyword (is, "length", len, true) && len >= 0)
1939  {
1940  if (len > 0)
1941  {
1942  for (octave_idx_type i = 0; i < len; i++)
1943  {
1944  octave_value t2;
1945  bool dummy;
1946 
1947  std::string name = read_text_data (is, "", dummy, t2, i);
1948 
1949  if (! is)
1950  error ("load: failed to load anonymous function handle");
1951 
1952  m_local_vars[name] = t2;
1953  }
1954  }
1955  }
1956  else
1957  {
1958  is.seekg (pos);
1959  is.clear ();
1960  }
1961 
1962  if (is)
1963  return parse (buf);
1964 
1965  return false;
1966  }
1967 
1968  bool anonymous_fcn_handle::save_binary (std::ostream& os, bool save_as_floats)
1969  {
1970  // FIXME: can we ensure that m_fcn is always defined?
1971 
1972  if (m_fcn.is_undefined ())
1973  return false;
1974 
1975  std::ostringstream nmbuf;
1976 
1977  size_t varlen = m_local_vars.size ();
1978 
1979  nmbuf << anonymous;
1980  if (varlen > 0)
1981  nmbuf << ' ' << varlen;
1982 
1983  std::string buf_str = nmbuf.str ();
1984  int32_t tmp = buf_str.length ();
1985  os.write (reinterpret_cast<char *> (&tmp), 4);
1986  os.write (buf_str.c_str (), buf_str.length ());
1987 
1988  std::ostringstream buf;
1989  print_raw (buf, true, 0);
1990  std::string stmp = buf.str ();
1991  tmp = stmp.length ();
1992  os.write (reinterpret_cast<char *> (&tmp), 4);
1993  os.write (stmp.c_str (), stmp.length ());
1994 
1995  if (varlen > 0)
1996  {
1997  for (const auto& nm_val : m_local_vars)
1998  {
1999  if (! save_binary_data (os, nm_val.second, nm_val.first,
2000  "", 0, save_as_floats))
2001  return ! os.fail ();
2002  }
2003  }
2004 
2005  return true;
2006  }
2007 
2008  bool anonymous_fcn_handle::load_binary (std::istream& is, bool swap,
2010  {
2011  // Read extra characters in m_name as the number of local variable
2012  // values in this anonymous function.
2013 
2014  octave_idx_type len = 0;
2015  size_t anl = anonymous.length ();
2016  if (m_name.length () > anl)
2017  {
2018  std::istringstream nm_is (m_name.substr (anl));
2019  nm_is >> len;
2020 
2021  // Anonymous functons don't have names. We just used this
2022  // string as temporary storage to pass the number of local
2023  // variable values.
2024 
2025  m_name = "";
2026  }
2027 
2028  int32_t tmp;
2029 
2030  if (! is.read (reinterpret_cast<char *> (&tmp), 4))
2031  return false;
2032  if (swap)
2033  swap_bytes<4> (&tmp);
2034 
2035  OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1);
2036  // is.get (ctmp2, tmp+1, 0); caused is.eof () to be true though
2037  // effectively not reading over file end
2038  is.read (ctmp2, tmp);
2039  ctmp2[tmp] = 0;
2040 
2041  unwind_protect_safe frame;
2042 
2043  // Set up temporary scope to use for evaluating the text that
2044  // defines the anonymous function.
2045 
2046  interpreter& interp
2047  = __get_interpreter__ ("anonymous_fcn_handle::load_binary");
2048 
2049  tree_evaluator& tw = interp.get_evaluator ();
2050 
2051  tw.push_dummy_scope (ctmp2);
2053 
2054  if (len > 0)
2055  {
2056  for (octave_idx_type i = 0; i < len; i++)
2057  {
2058  octave_value t2;
2059  bool dummy;
2060  std::string doc;
2061 
2062  std::string name
2063  = read_binary_data (is, swap, fmt, "", dummy, t2, doc);
2064 
2065  if (! is)
2066  error ("load: failed to load anonymous function handle");
2067 
2068  m_local_vars[name] = t2;
2069  }
2070  }
2071 
2072  if (is)
2073  return parse (ctmp2);
2074 
2075  return false;
2076  }
2077 
2079  const char *name, bool save_as_floats)
2080  {
2081 #if defined (HAVE_HDF5)
2082 
2083  bool retval = true;
2084 
2085  octave_hdf5_id group_hid = -1;
2086 #if defined (HAVE_HDF5_18)
2087  group_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT,
2089 #else
2090  group_hid = H5Gcreate (loc_id, name, 0);
2091 #endif
2092  if (group_hid < 0)
2093  return false;
2094 
2095  octave_hdf5_id space_hid, data_hid, type_hid;
2096  space_hid = data_hid = type_hid = -1;
2097 
2098  // attach the type of the variable
2099  type_hid = H5Tcopy (H5T_C_S1);
2100  H5Tset_size (type_hid, m_name.length () + 1);
2101  if (type_hid < 0)
2102  {
2103  H5Gclose (group_hid);
2104  return false;
2105  }
2106 
2107  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2);
2108  hdims[0] = 0;
2109  hdims[1] = 0;
2110  space_hid = H5Screate_simple (0, hdims, nullptr);
2111  if (space_hid < 0)
2112  {
2113  H5Tclose (type_hid);
2114  H5Gclose (group_hid);
2115  return false;
2116  }
2117 #if defined (HAVE_HDF5_18)
2118  data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid,
2121 #else
2122  data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid,
2124 #endif
2125  if (data_hid < 0
2126  || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
2127  octave_H5P_DEFAULT, m_name.c_str ()) < 0)
2128  {
2129  H5Sclose (space_hid);
2130  H5Tclose (type_hid);
2131  H5Gclose (group_hid);
2132  return false;
2133  }
2134  H5Dclose (data_hid);
2135 
2136  std::ostringstream buf;
2137  print_raw (buf, true, 0);
2138  std::string stmp = buf.str ();
2139 
2140  // attach the type of the variable
2141  H5Tset_size (type_hid, stmp.length () + 1);
2142  if (type_hid < 0)
2143  {
2144  H5Sclose (space_hid);
2145  H5Gclose (group_hid);
2146  return false;
2147  }
2148 
2149 #if defined (HAVE_HDF5_18)
2150  data_hid = H5Dcreate (group_hid, "fcn", type_hid, space_hid,
2153 #else
2154  data_hid = H5Dcreate (group_hid, "fcn", type_hid, space_hid,
2156 #endif
2157  if (data_hid < 0
2158  || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
2159  octave_H5P_DEFAULT, stmp.c_str ()) < 0)
2160  {
2161  H5Sclose (space_hid);
2162  H5Tclose (type_hid);
2163  H5Gclose (group_hid);
2164  return false;
2165  }
2166 
2167  H5Dclose (data_hid);
2168 
2169  size_t varlen = m_local_vars.size ();
2170 
2171  if (varlen > 0)
2172  {
2173  octave_hdf5_id as_id = H5Screate (H5S_SCALAR);
2174 
2175  if (as_id >= 0)
2176  {
2177  octave_hdf5_id a_id;
2178 #if defined (HAVE_HDF5_18)
2179  a_id = H5Acreate (group_hid, "SYMBOL_TABLE", H5T_NATIVE_IDX, as_id,
2181 
2182 #else
2183  a_id = H5Acreate (group_hid, "SYMBOL_TABLE", H5T_NATIVE_IDX, as_id,
2185 #endif
2186 
2187  if (a_id >= 0)
2188  {
2189  retval = (H5Awrite (a_id, H5T_NATIVE_IDX, &varlen) >= 0);
2190 
2191  H5Aclose (a_id);
2192  }
2193  else
2194  retval = false;
2195 
2196  H5Sclose (as_id);
2197  }
2198  else
2199  retval = false;
2200 #if defined (HAVE_HDF5_18)
2201  data_hid = H5Gcreate (group_hid, "symbol table",
2203 #else
2204  data_hid = H5Gcreate (group_hid, "symbol table", 0);
2205 #endif
2206  if (data_hid < 0)
2207  {
2208  H5Sclose (space_hid);
2209  H5Tclose (type_hid);
2210  H5Gclose (group_hid);
2211  return false;
2212  }
2213 
2214  for (const auto& nm_val : m_local_vars)
2215  {
2216  if (! add_hdf5_data (data_hid, nm_val.second, nm_val.first,
2217  "", false, save_as_floats))
2218  break;
2219  }
2220 
2221  H5Gclose (data_hid);
2222  }
2223 
2224  H5Sclose (space_hid);
2225  H5Tclose (type_hid);
2226  H5Gclose (group_hid);
2227 
2228  return retval;
2229 
2230 #else
2231 
2232  octave_unused_parameter (loc_id);
2233  octave_unused_parameter (name);
2234  octave_unused_parameter (save_as_floats);
2235 
2236  warn_save ("hdf5");
2237 
2238  return false;
2239 
2240 #endif
2241  }
2242 
2244  octave_hdf5_id& space_hid,
2245  octave_hdf5_id& type_hid)
2246  {
2247 #if defined (HAVE_HDF5)
2248 
2249  bool success = true;
2250 
2251 #if defined (HAVE_HDF5_18)
2252  octave_hdf5_id data_hid = H5Dopen (group_hid, "fcn", octave_H5P_DEFAULT);
2253 #else
2254  octave_hdf5_id data_hid = H5Dopen (group_hid, "fcn");
2255 #endif
2256 
2257  if (data_hid < 0)
2258  {
2259  H5Sclose (space_hid);
2260  H5Tclose (type_hid);
2261  H5Gclose (group_hid);
2262  return false;
2263  }
2264 
2265  H5Tclose (type_hid);
2266  type_hid = H5Dget_type (data_hid);
2267  octave_hdf5_id type_class_hid = H5Tget_class (type_hid);
2268 
2269  if (type_class_hid != H5T_STRING)
2270  {
2271  H5Sclose (space_hid);
2272  H5Tclose (type_hid);
2273  H5Dclose (data_hid);
2274  H5Gclose (group_hid);
2275  return false;
2276  }
2277 
2278  H5Sclose (space_hid);
2279  space_hid = H5Dget_space (data_hid);
2280  hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
2281 
2282  if (rank != 0)
2283  {
2284  H5Sclose (space_hid);
2285  H5Tclose (type_hid);
2286  H5Dclose (data_hid);
2287  H5Gclose (group_hid);
2288  return false;
2289  }
2290 
2291  int slen = H5Tget_size (type_hid);
2292  if (slen < 0)
2293  {
2294  H5Sclose (space_hid);
2295  H5Tclose (type_hid);
2296  H5Dclose (data_hid);
2297  H5Gclose (group_hid);
2298  return false;
2299  }
2300 
2301  OCTAVE_LOCAL_BUFFER (char, fcn_tmp, slen);
2302 
2303  // create datatype for (null-terminated) string to read into:
2304  octave_hdf5_id st_id = H5Tcopy (H5T_C_S1);
2305  H5Tset_size (st_id, slen);
2306 
2307  if (H5Dread (data_hid, st_id, octave_H5S_ALL, octave_H5S_ALL,
2308  octave_H5P_DEFAULT, fcn_tmp)
2309  < 0)
2310  {
2311  H5Tclose (st_id);
2312  H5Sclose (space_hid);
2313  H5Tclose (type_hid);
2314  H5Dclose (data_hid);
2315  H5Gclose (group_hid);
2316  return false;
2317  }
2318  H5Tclose (st_id);
2319  H5Dclose (data_hid);
2320 
2321  octave_idx_type len = 0;
2322 
2323  // we have to pull some shenanigans here to make sure
2324  // HDF5 doesn't print out all sorts of error messages if we
2325  // call H5Aopen for a non-existing attribute
2326 
2327  H5E_auto_t err_func;
2328  void *err_func_data;
2329 
2330  // turn off error reporting temporarily, but save the error
2331  // reporting function:
2332 #if defined (HAVE_HDF5_18)
2333  H5Eget_auto (octave_H5E_DEFAULT, &err_func, &err_func_data);
2334  H5Eset_auto (octave_H5E_DEFAULT, nullptr, nullptr);
2335 #else
2336  H5Eget_auto (&err_func, &err_func_data);
2337  H5Eset_auto (nullptr, nullptr);
2338 #endif
2339 
2340  octave_hdf5_id attr_id = H5Aopen_name (group_hid, "SYMBOL_TABLE");
2341 
2342  if (attr_id >= 0)
2343  {
2344  if (H5Aread (attr_id, H5T_NATIVE_IDX, &len) < 0)
2345  success = false;
2346 
2347  H5Aclose (attr_id);
2348  }
2349 
2350  // restore error reporting:
2351 #if defined (HAVE_HDF5_18)
2352  H5Eset_auto (octave_H5E_DEFAULT, err_func, err_func_data);
2353 #else
2354  H5Eset_auto (err_func, err_func_data);
2355 #endif
2356 
2357  unwind_protect_safe frame;
2358 
2359  // Set up temporary scope to use for evaluating the text that
2360  // defines the anonymous function.
2361 
2362  interpreter& interp
2363  = __get_interpreter__ ("anonymous_fcn_handle::load_hdf5");
2364 
2365  tree_evaluator& tw = interp.get_evaluator ();
2366 
2367  tw.push_dummy_scope (fcn_tmp);
2369 
2370  if (len > 0 && success)
2371  {
2372  hsize_t num_obj = 0;
2373 #if defined (HAVE_HDF5_18)
2374  data_hid = H5Gopen (group_hid, "symbol table", octave_H5P_DEFAULT);
2375 #else
2376  data_hid = H5Gopen (group_hid, "symbol table");
2377 #endif
2378  H5Gget_num_objs (data_hid, &num_obj);
2379  H5Gclose (data_hid);
2380 
2381  if (num_obj != static_cast<hsize_t> (len))
2382  error ("load: failed to load anonymous function handle");
2383 
2384  hdf5_callback_data dsub;
2385  int current_item = 0;
2386  for (octave_idx_type i = 0; i < len; i++)
2387  {
2388  if (hdf5_h5g_iterate (group_hid, "symbol table", &current_item,
2389  &dsub) <= 0)
2390  error ("load: failed to load anonymous function handle");
2391 
2392  m_local_vars[dsub.name] = dsub.tc;
2393  }
2394  }
2395 
2396  if (success)
2397  return parse (fcn_tmp);
2398 
2399  return false;
2400 
2401 #else
2402 
2403  octave_unused_parameter (group_hid);
2404  octave_unused_parameter (space_hid);
2405  octave_unused_parameter (type_hid);
2406 
2407  return false;
2408 
2409 #endif
2410  }
2411 
2412  void anonymous_fcn_handle::print_raw (std::ostream& os, bool, int) const
2413  {
2414  tree_print_code tpc (os);
2415 
2417 
2418  if (! f)
2419  error ("invalid anonymous function handle");
2420 
2421  os << "@";
2422 
2423  // The parameter list should always be valid for anonymous
2424  // functions, so we should always call accept for it, and it will
2425  // print the parens for us.
2426 
2427  tree_parameter_list *p = f->parameter_list ();
2428 
2429  if (p)
2430  p->accept (tpc);
2431 
2432  os << " ";
2433 
2434  tree_statement_list *b = f->body ();
2435 
2436  assert (b->length () == 1);
2437 
2438  tree_statement *s = b->front ();
2439 
2440  if (! s)
2441  error ("invalid anonymous function handle");
2442 
2443  assert (s->is_expression ());
2444 
2445  tree_expression *e = s->expression ();
2446 
2447  if (! e)
2448  error ("invalid anonymous function handle");
2449 
2450  tpc.print_fcn_handle_body (e);
2451  }
2452 
2453  bool
2454  anonymous_fcn_handle::parse (const std::string& fcn_text)
2455  {
2456  // FIXME: If evaluation of the string gives us an anonymous function
2457  // handle object, then why extract the function and create a new
2458  // anonymous function object? Why not just attach the workspace
2459  // values to the object returned by eval_string? This code is also is
2460  // duplicated in read_mat5_binary_element in ls-mat5.cc.
2461 
2462  interpreter& interp = __get_interpreter__ ("anonymous_fcn_handle::parse");
2463 
2464  // Set up temporary scope to use for evaluating the text that defines
2465  // the anonymous function so that we don't pick up values of random
2466  // variables that might be in the current scope.
2467 
2468  tree_evaluator& tw = interp.get_evaluator ();
2469  tw.push_dummy_scope ("read_mat5_binary_element");
2470 
2471  unwind_action act ([&tw] () { tw.pop_scope (); });
2472 
2473  int parse_status;
2474  octave_value anonymous_fcn_hdl
2475  = interp.eval_string (fcn_text, true, parse_status);
2476 
2477  if (parse_status != 0)
2478  return false;
2479 
2480  octave_fcn_handle *fh = anonymous_fcn_hdl.fcn_handle_value ();
2481 
2482  if (! fh)
2483  return false;
2484 
2485  m_fcn = fh->fcn_val ();
2486 
2488 
2489  if (uf)
2490  {
2491  symbol_scope uf_scope = uf->scope ();
2492 
2493  if (uf_scope)
2494  uf_scope.cache_name (m_name);
2495  }
2496 
2497  return true;
2498  }
2499 
2501  const anonymous_fcn_handle& fh2)
2502  {
2503  if (fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
2504  return fh1.m_fcn.is_copy_of (fh2.m_fcn);
2505  else
2506  return false;
2507  }
2508 }
2509 
2511  : octave_base_value (), m_rep (new octave::invalid_fcn_handle ())
2512 { }
2513 
2515  : octave_base_value (), m_rep (new octave::internal_fcn_handle (fcn))
2516 { }
2517 
2519  : octave_base_value (), m_rep (new octave::simple_fcn_handle (name))
2520 { }
2521 
2523  const std::string& name)
2524  : octave_base_value (), m_rep (new octave::simple_fcn_handle (fcn, name))
2525 { }
2526 
2527 octave_fcn_handle::octave_fcn_handle (const std::string& class_nm,
2528  const std::string& meth_nm)
2529  : octave_base_value (),
2530  m_rep (new octave::class_simple_fcn_handle (class_nm, meth_nm))
2531 { }
2532 
2534  const std::string& class_nm,
2535  const std::string& meth_nm)
2536  : octave_base_value (),
2537  m_rep (new octave::class_simple_fcn_handle (fcn, class_nm, meth_nm))
2538 { }
2539 
2541  const octave_value& fcn,
2542  const std::string& class_nm,
2543  const std::string& meth_nm)
2544  : octave_base_value (),
2545  m_rep (new octave::class_simple_fcn_handle (obj, fcn, class_nm, meth_nm))
2546 { }
2547 
2549  const std::string& name,
2550  const std::list<std::string>& parentage)
2551  : octave_base_value (),
2552  m_rep (new octave::scoped_fcn_handle (fcn, name, parentage))
2553 { }
2554 
2556  const std::string& name,
2557  const std::shared_ptr<octave::stack_frame>& closure_frames)
2558  : octave_base_value (),
2559  m_rep (new octave::nested_fcn_handle (fcn, name, closure_frames))
2560 { }
2561 
2563  const octave::stack_frame::local_vars_map& local_vars)
2564  : octave_base_value (),
2565  m_rep (new octave::anonymous_fcn_handle (fcn, local_vars))
2566 { }
2567 
2569  : octave_base_value (), m_rep (rep)
2570 { }
2571 
2573  : octave_base_value (fh)
2574 {
2575  m_rep.reset (fh.m_rep->clone ());
2576 }
2577 
2578 dim_vector
2580 {
2581  static dim_vector dv (1, 1);
2582  return dv;
2583 }
2584 
2585 bool
2587 {
2588  return m_rep->save_ascii (os);
2589 }
2590 
2591 bool
2593 {
2594  std::shared_ptr<octave::base_fcn_handle> new_rep;
2595 
2596  // Read enough to detect type then create new rep object and dispatch
2597  // to finish loading object.
2598 
2599  std::streampos pos = is.tellg ();
2600 
2601  std::string octaveroot = extract_keyword (is, "octaveroot", true);
2602  if (octaveroot.empty ())
2603  {
2604  is.seekg (pos);
2605  is.clear ();
2606  }
2607 
2608  pos = is.tellg ();
2609 
2610  std::string fpath = extract_keyword (is, "path", true);
2611  if (fpath.empty ())
2612  {
2613  is.seekg (pos);
2614  is.clear ();
2615  }
2616 
2617  if (! (octaveroot.empty () || fpath.empty ()))
2618  {
2619  size_t len = octaveroot.size ();
2620  if (octaveroot == fpath.substr (0, len))
2621  fpath = octave::config::octave_exec_home () + fpath.substr (len);
2622  }
2623 
2624  pos = is.tellg ();
2625 
2626  std::string subtype = extract_keyword (is, "subtype", true);
2627  if (subtype.empty ())
2628  {
2629  is.seekg (pos);
2630  is.clear ();
2631 
2632  // We have a legacy file that can contain either an anonymous
2633  // function or a simple function handle.
2634 
2635  std::string name;
2636  is >> name;
2637 
2638  if (name == anonymous)
2639  new_rep.reset (new octave::anonymous_fcn_handle ());
2640  else
2641  new_rep.reset (new octave::simple_fcn_handle (name, fpath, octaveroot));
2642  }
2643  else
2644  {
2645  // Load individual function handle types.
2646 
2647  if (subtype == "simple")
2648  {
2649  std::string name;
2650  is >> name;
2651 
2652  new_rep.reset (new octave::simple_fcn_handle (name, fpath, octaveroot));
2653  }
2654  else if (subtype == "scopedfunction")
2655  {
2656  std::string name;
2657  is >> name;
2658 
2659  new_rep.reset (new octave::scoped_fcn_handle (name, fpath, octaveroot));
2660  }
2661  else if (subtype == "anonymous")
2662  new_rep.reset (new octave::anonymous_fcn_handle ());
2663  else if (subtype == "nested")
2664  {
2665  std::string name;
2666  is >> name;
2667 
2668  new_rep.reset (new octave::nested_fcn_handle (name, fpath, octaveroot));
2669  }
2670  else if (subtype == "classsimple")
2671  {
2672  std::string name;
2673  is >> name;
2674 
2675  new_rep.reset (new octave::class_simple_fcn_handle (name, fpath, octaveroot));
2676  }
2677  }
2678 
2679  if (! new_rep)
2680  return false;
2681 
2682  if (! new_rep->load_ascii (is))
2683  return false;
2684 
2685  m_rep = new_rep;
2686 
2687  return true;
2688 }
2689 
2690 bool
2691 octave_fcn_handle::save_binary (std::ostream& os, bool save_as_floats)
2692 {
2693  return m_rep->save_binary (os, save_as_floats);
2694 }
2695 
2696 bool
2697 octave_fcn_handle::load_binary (std::istream& is, bool swap,
2699 {
2700  // Read enough to detect type then create new rep object and dispatch
2701  // to finish loading object.
2702 
2703  int32_t tmp;
2704  if (! is.read (reinterpret_cast<char *> (&tmp), 4))
2705  return false;
2706  if (swap)
2707  swap_bytes<4> (&tmp);
2708 
2709  OCTAVE_LOCAL_BUFFER (char, ctmp1, tmp+1);
2710  // is.get (ctmp1, tmp+1, 0); caused is.eof () to be true though
2711  // effectively not reading over file end
2712  is.read (ctmp1, tmp);
2713  ctmp1[tmp] = 0;
2714  std::string name (ctmp1);
2715 
2716  if (! is)
2717  return false;
2718 
2719  std::shared_ptr<octave::base_fcn_handle> new_rep;
2720 
2721  size_t anl = anonymous.length ();
2722 
2723  if (name.length () >= anl && name.substr (0, anl) == anonymous)
2724  {
2725  // Even with extra info stored in the function name, anonymous
2726  // functions look the same. Note that NAME here may have the
2727  // number of local variables appended. We decode that inside the
2728  // load_binary function.
2729 
2730  new_rep.reset (new octave::anonymous_fcn_handle (name));
2731  }
2732  else
2733  {
2734  // Unpack extra info stored with the function name and load
2735  // individual function handle types.
2736  // FIXME: is there a better way?
2737 
2738  std::string octaveroot;
2739  std::string fpath;
2740  std::string subtype = "simple";
2741 
2742  if (name.find_first_of ('\n') != std::string::npos)
2743  {
2744  size_t pos1 = name.find_first_of ('\n');
2745  size_t pos2 = name.find_first_of ('\n', pos1 + 1);
2746  octaveroot = name.substr (pos1 + 1, pos2 - pos1 - 1);
2747  fpath = name.substr (pos2 + 1);
2748  name = name.substr (0, pos1);
2749  }
2750 
2751  size_t pos1 = name.find ('@');
2752  if (pos1 != std::string::npos)
2753  {
2754  if (name[pos1+1] == '<')
2755  {
2756  size_t pos2 = name.find ('>', pos1 + 2);
2757 
2758  if (pos2 != std::string::npos)
2759  subtype = name.substr (pos1 + 2, pos2 - pos1 - 2);
2760  }
2761 
2762  name = name.substr (0, pos1);
2763  }
2764 
2765  // Anonymous should have been handled above so it is not in the
2766  // following list.
2767 
2768  if (subtype == "simple")
2769  new_rep.reset (new octave::simple_fcn_handle (name, fpath, octaveroot));
2770  else if (subtype == "scopedfunction")
2771  new_rep.reset (new octave::scoped_fcn_handle (name, fpath, octaveroot));
2772  else if (subtype == "nested")
2773  new_rep.reset (new octave::nested_fcn_handle (name, fpath, octaveroot));
2774  else if (subtype == "classsimple")
2775  new_rep.reset (new octave::class_simple_fcn_handle (name, fpath, octaveroot));
2776  }
2777 
2778  if (! new_rep)
2779  return false;
2780 
2781  if (! new_rep->load_binary (is, swap, fmt))
2782  return false;
2783 
2784  m_rep = new_rep;
2785 
2786  return true;
2787 }
2788 
2789 bool
2791  bool save_as_floats)
2792 {
2793  return m_rep->save_hdf5 (loc_id, name, save_as_floats);
2794 }
2795 
2796 bool
2797 octave_fcn_handle::load_hdf5 (octave_hdf5_id loc_id, const char *name_arg)
2798 {
2799 #if defined (HAVE_HDF5)
2800 
2801 #if defined (HAVE_HDF5_18)
2802  octave_hdf5_id group_hid = H5Gopen (loc_id, name_arg, octave_H5P_DEFAULT);
2803 #else
2804  octave_hdf5_id group_hid = H5Gopen (loc_id, name_arg);
2805 #endif
2806  if (group_hid < 0)
2807  return false;
2808 
2809 #if defined (HAVE_HDF5_18)
2810  octave_hdf5_id data_hid = H5Dopen (group_hid, "nm", octave_H5P_DEFAULT);
2811 #else
2812  octave_hdf5_id data_hid = H5Dopen (group_hid, "nm");
2813 #endif
2814 
2815  if (data_hid < 0)
2816  {
2817  H5Gclose (group_hid);
2818  return false;
2819  }
2820 
2821  octave_hdf5_id type_hid = H5Dget_type (data_hid);
2822  octave_hdf5_id type_class_hid = H5Tget_class (type_hid);
2823 
2824  if (type_class_hid != H5T_STRING)
2825  {
2826  H5Tclose (type_hid);
2827  H5Dclose (data_hid);
2828  H5Gclose (group_hid);
2829  return false;
2830  }
2831 
2832  octave_hdf5_id space_hid = H5Dget_space (data_hid);
2833  hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
2834 
2835  if (rank != 0)
2836  {
2837  H5Sclose (space_hid);
2838  H5Tclose (type_hid);
2839  H5Dclose (data_hid);
2840  H5Gclose (group_hid);
2841  return false;
2842  }
2843 
2844  int slen = H5Tget_size (type_hid);
2845  if (slen < 0)
2846  {
2847  H5Sclose (space_hid);
2848  H5Tclose (type_hid);
2849  H5Dclose (data_hid);
2850  H5Gclose (group_hid);
2851  return false;
2852  }
2853 
2854  OCTAVE_LOCAL_BUFFER (char, nm_tmp, slen);
2855 
2856  // create datatype for (null-terminated) string to read into:
2857  octave_hdf5_id st_id = H5Tcopy (H5T_C_S1);
2858  H5Tset_size (st_id, slen);
2859 
2860  if (H5Dread (data_hid, st_id, octave_H5S_ALL, octave_H5S_ALL,
2861  octave_H5P_DEFAULT, nm_tmp)
2862  < 0)
2863  {
2864  H5Tclose (st_id);
2865  H5Sclose (space_hid);
2866  H5Tclose (type_hid);
2867  H5Dclose (data_hid);
2868  H5Gclose (group_hid);
2869  return false;
2870  }
2871  H5Tclose (st_id);
2872  H5Dclose (data_hid);
2873 
2874  std::string name (nm_tmp);
2875 
2876  std::shared_ptr<octave::base_fcn_handle> new_rep;
2877 
2878  if (name == anonymous)
2879  {
2880  // Even with extra info stored in the function name, anonymous
2881  // functions look the same.
2882 
2883  new_rep.reset (new octave::anonymous_fcn_handle ());
2884  }
2885  else
2886  {
2887  // Unpack extra info stored with the function name and load
2888  // individual function handle types.
2889  // FIXME: is there a better way?
2890 
2891  std::string octaveroot;
2892  std::string fpath;
2893  std::string subtype = "simple";
2894 
2895  if (name.find_first_of ('\n') != std::string::npos)
2896  {
2897  size_t pos1 = name.find_first_of ('\n');
2898  size_t pos2 = name.find_first_of ('\n', pos1 + 1);
2899  octaveroot = name.substr (pos1 + 1, pos2 - pos1 - 1);
2900  fpath = name.substr (pos2 + 1);
2901  name = name.substr (0, pos1);
2902  }
2903 
2904  size_t pos1 = name.find ('@');
2905  if (pos1 != std::string::npos)
2906  {
2907  if (name[pos1+1] == '<')
2908  {
2909  size_t pos2 = name.find ('>', pos1 + 2);
2910 
2911  if (pos2 != std::string::npos)
2912  subtype = name.substr (pos1 + 2, pos2 - pos1 - 2);
2913  }
2914 
2915  name = name.substr (0, pos1);
2916  }
2917 
2918  // Anonymous should have been handled above so it is not in the
2919  // following list.
2920 
2921  if (subtype == "simple")
2922  new_rep.reset (new octave::simple_fcn_handle (name, fpath, octaveroot));
2923  else if (subtype == "scopedfunction")
2924  new_rep.reset (new octave::scoped_fcn_handle (name, fpath, octaveroot));
2925  else if (subtype == "nested")
2926  new_rep.reset (new octave::nested_fcn_handle (name, fpath, octaveroot));
2927  else if (subtype == "classsimple")
2928  new_rep.reset (new octave::class_simple_fcn_handle (name, fpath, octaveroot));
2929  }
2930 
2931  bool status = false;
2932 
2933  if (new_rep && new_rep->load_hdf5 (group_hid, space_hid, type_hid))
2934  {
2935  m_rep = new_rep;
2936  status = true;
2937  }
2938 
2939  // FIXME: manage these with an unwind_action object?
2940 
2941  H5Tclose (type_hid);
2942  H5Sclose (space_hid);
2943  H5Gclose (group_hid);
2944 
2945  return status;
2946 
2947 #else
2948 
2949  octave_unused_parameter (loc_id);
2950  octave_unused_parameter (name_arg);
2951 
2952  warn_load ("hdf5");
2953 
2954  return false;
2955 
2956 #endif
2957 }
2958 
2959 /*
2960 %!test <*33857>
2961 %! a = 2;
2962 %! f = @(x) a + x;
2963 %! g = @(x) 2 * x;
2964 %! hm = @version;
2965 %! hdld = @svd;
2966 %! hbi = @log2;
2967 %! f2 = f;
2968 %! g2 = g;
2969 %! hm2 = hm;
2970 %! hdld2 = hdld;
2971 %! hbi2 = hbi;
2972 %! modes = {"-text", "-binary"};
2973 %! if (isfield (__octave_config_info__, "HAVE_HDF5")
2974 %! && __octave_config_info__ ("HAVE_HDF5"))
2975 %! modes(end+1) = "-hdf5";
2976 %! endif
2977 %! for i = 1:numel (modes)
2978 %! mode = modes{i};
2979 %! nm = tempname ();
2980 %! unwind_protect
2981 %! f2 (1);
2982 %! save (mode, nm, "f2", "g2", "hm2", "hdld2", "hbi2");
2983 %! clear f2 g2 hm2 hdld2 hbi2
2984 %! load (nm);
2985 %! assert (f (2), f2 (2));
2986 %! assert (g (2), g2 (2));
2987 %! assert (g (3), g2 (3));
2988 %! unlink (nm);
2989 %! save (mode, nm, "f2", "g2", "hm2", "hdld2", "hbi2");
2990 %! unwind_protect_cleanup
2991 %! unlink (nm);
2992 %! end_unwind_protect
2993 %! endfor
2994 */
2995 
2996 /*
2997 %!function fcn_handle_save_recurse (n, mode, nm, f2, g2, hm2, hdld2, hbi2)
2998 %! if (n == 0)
2999 %! save (mode, nm, "f2", "g2", "hm2", "hdld2", "hbi2");
3000 %! else
3001 %! fcn_handle_save_recurse (n - 1, mode, nm, f2, g2, hm2, hdld2, hbi2);
3002 %! endif
3003 %!endfunction
3004 %!function [f2, g2, hm2, hdld2, hbi2] = fcn_handle_load_recurse (n, nm)
3005 %! if (n == 0)
3006 %! load (nm);
3007 %! else
3008 %! [f2, g2, hm2, hdld2, hbi2] = fcn_handle_load_recurse (n - 1, nm);
3009 %! endif
3010 %!endfunction
3011 
3012 %!test <*35876>
3013 %! a = 2;
3014 %! f = @(x) a + x;
3015 %! g = @(x) 2 * x;
3016 %! hm = @version;
3017 %! hdld = @svd;
3018 %! hbi = @log2;
3019 %! f2 = f;
3020 %! g2 = g;
3021 %! hm2 = hm;
3022 %! hdld2 = hdld;
3023 %! hbi2 = hbi;
3024 %! modes = {"-text", "-binary"};
3025 %! if (isfield (__octave_config_info__, "HAVE_HDF5")
3026 %! && __octave_config_info__ ("HAVE_HDF5"))
3027 %! modes(end+1) = "-hdf5";
3028 %! endif
3029 %! for i = 1:numel (modes)
3030 %! mode = modes{i};
3031 %! nm = tempname ();
3032 %! unwind_protect
3033 %! fcn_handle_save_recurse (2, mode, nm, f2, g2, hm2, hdld2, hbi2);
3034 %! clear f2 g2 hm2 hdld2 hbi2
3035 %! [f2, f2, hm2, hdld2, hbi2] = fcn_handle_load_recurse (2, nm);
3036 %! load (nm);
3037 %! assert (f (2), f2 (2));
3038 %! assert (g (2), g2 (2));
3039 %! assert (g (3), g2 (3));
3040 %! unlink (nm);
3041 %! fcn_handle_save_recurse (2, mode, nm, f2, g2, hm2, hdld2, hbi2);
3042 %! unwind_protect_cleanup
3043 %! unlink (nm);
3044 %! end_unwind_protect
3045 %! endfor
3046 */
3047 
3048 void
3049 octave_fcn_handle::print (std::ostream& os, bool pr_as_read_syntax)
3050 {
3051  print_raw (os, pr_as_read_syntax);
3052  newline (os);
3053 }
3054 
3055 void
3056 octave_fcn_handle::print_raw (std::ostream& os, bool pr_as_read_syntax) const
3057 {
3058  m_rep->print_raw (os, pr_as_read_syntax, current_print_indent_level ());
3059 }
3060 
3061 bool
3063 {
3064  // FIXME: Maybe there is a better way? Possibly by using typeid or
3065  // typeindex?
3066 
3067  // Don't include invalid_fcn_handle in the list of types to compare.
3068  // Consider them to be like NaN values so comparisons between any two
3069  // invalid handles are always false.
3070 
3071  if (fh1.is_internal () && fh2.is_internal ())
3072  return is_equal_to (*dynamic_cast<octave::internal_fcn_handle *> (fh1.get_rep ()),
3073  *dynamic_cast<octave::internal_fcn_handle *> (fh2.get_rep ()));
3074  else if (fh1.is_simple () && fh2.is_simple ())
3075  return is_equal_to (*dynamic_cast<octave::simple_fcn_handle *> (fh1.get_rep ()),
3076  *dynamic_cast<octave::simple_fcn_handle *> (fh2.get_rep ()));
3077  else if (fh1.is_scoped () && fh2.is_scoped ())
3078  return is_equal_to (*dynamic_cast<octave::scoped_fcn_handle *> (fh1.get_rep ()),
3079  *dynamic_cast<octave::scoped_fcn_handle *> (fh2.get_rep ()));
3080  else if (fh1.is_nested () && fh2.is_nested ())
3081  return is_equal_to (*dynamic_cast<octave::nested_fcn_handle *> (fh1.get_rep ()),
3082  *dynamic_cast<octave::nested_fcn_handle *> (fh2.get_rep ()));
3083  else if (fh1.is_class_simple () && fh2.is_class_simple ())
3084  return is_equal_to (*dynamic_cast<octave::class_simple_fcn_handle *> (fh1.get_rep ()),
3085  *dynamic_cast<octave::class_simple_fcn_handle *> (fh2.get_rep ()));
3086  else if (fh1.is_anonymous () && fh2.is_anonymous ())
3087  return is_equal_to (*dynamic_cast<octave::anonymous_fcn_handle *> (fh1.get_rep ()),
3088  *dynamic_cast<octave::anonymous_fcn_handle *> (fh2.get_rep ()));
3089  else
3090  return false;
3091 }
3092 
3093 namespace octave
3094 {
3095  // DEPRECATED in Octave 6.
3096 
3097  octave_value
3098  make_fcn_handle (interpreter& interp, const std::string& nm)
3099  {
3100  tree_evaluator& tw = interp.get_evaluator ();
3101 
3102  return tw.make_fcn_handle (nm);
3103  }
3104 }
3105 
3106 DEFUN (functions, args, ,
3107  doc: /* -*- texinfo -*-
3108 @deftypefn {} {@var{s} =} functions (@var{fcn_handle})
3109 Return a structure containing information about the function handle
3110 @var{fcn_handle}.
3111 
3112 The structure @var{s} always contains these three fields:
3113 
3114 @table @asis
3115 @item function
3116 The function name. For an anonymous function (no name) this will be the
3117 actual function definition.
3118 
3119 @item type
3120 Type of the function.
3121 
3122 @table @asis
3123 @item anonymous
3124 The function is anonymous.
3125 
3126 @item private
3127 The function is private.
3128 
3129 @item overloaded
3130 The function overloads an existing function.
3131 
3132 @item simple
3133 The function is a built-in or m-file function.
3134 
3135 @item subfunction
3136 The function is a subfunction within an m-file.
3137 @end table
3138 
3139 @item nested
3140 The function is nested.
3141 
3142 @item file
3143 The m-file that will be called to perform the function. This field is empty
3144 for anonymous and built-in functions.
3145 @end table
3146 
3147 In addition, some function types may return more information in additional
3148 fields.
3149 
3150 @strong{Warning:} @code{functions} is provided for debugging purposes only.
3151 Its behavior may change in the future and programs should not depend on any
3152 particular output format.
3153 
3154 @seealso{func2str, str2func}
3155 @end deftypefn */)
3156 {
3157  if (args.length () != 1)
3158  print_usage ();
3159 
3160  octave_fcn_handle *fh = args(0).xfcn_handle_value ("functions: FCN_HANDLE argument must be a function handle object");
3161 
3162  return ovl (fh->info ());
3163 }
3164 
3165 DEFUN (func2str, args, ,
3166  doc: /* -*- texinfo -*-
3167 @deftypefn {} {} func2str (@var{fcn_handle})
3168 Return a string containing the name of the function referenced by the
3169 function handle @var{fcn_handle}.
3170 @seealso{str2func, functions}
3171 @end deftypefn */)
3172 {
3173  if (args.length () != 1)
3174  print_usage ();
3175 
3176  octave_fcn_handle *fh = args(0).xfcn_handle_value ("func2str: FCN_HANDLE argument must be a function handle object");
3177 
3178  if (! fh)
3179  error ("func2str: FCN_HANDLE must be a valid function handle");
3180 
3182 
3183  std::string fh_nm = fh->fcn_name ();
3184 
3185  if (fh->is_anonymous ())
3186  {
3187  std::ostringstream buf;
3188 
3189  fh->print_raw (buf);
3190 
3191  retval = buf.str ();
3192  }
3193  else
3194  retval = fh_nm;
3195 
3196  return retval;
3197 }
3198 
3199 DEFMETHOD (str2func, interp, args, ,
3200  doc: /* -*- texinfo -*-
3201 @deftypefn {} {} str2func (@var{fcn_name})
3202 Return a function handle constructed from the string @var{fcn_name}.
3203 
3204 Previous versions of Octave accepted an optional second argument,
3205 @qcode{"global"}, that caused str2func to ignore locally visible
3206 functions. This option is no longer supported.
3207 @seealso{func2str, functions}
3208 @end deftypefn */)
3209 {
3210  int nargin = args.length ();
3211 
3212  if (nargin < 1 || nargin > 2)
3213  print_usage ();
3214 
3215  std::string nm
3216  = args(0).xstring_value ("str2func: FCN_NAME must be a string");
3217 
3218  if (nm.empty ())
3219  error ("str2func: invalid function name");
3220 
3221  if (nm[0] == '@')
3222  {
3223  // Unlike the anonymous_fcn_handle::parse method, don't set up
3224  // temporary scope to use for evaluating the text that defines
3225  // the anonymous function. Here we want
3226  //
3227  // str2fun ("@(args) expr")
3228  //
3229  // to behave the same as if
3230  //
3231  // @(args) expr
3232  //
3233  // were evaluated in the current scope.
3234 
3235  int parse_status;
3236  octave_value afh = interp.eval_string (nm, true, parse_status);
3237 
3238  if (parse_status == 0)
3239  return afh;
3240  }
3241  else
3242  {
3243  if (nargin == 2)
3244  warning_with_id ("Octave:str2func-global-argument",
3245  "str2func: second argument ignored");
3246 
3247  octave::tree_evaluator& tw = interp.get_evaluator ();
3248 
3249  return tw.make_fcn_handle (nm);
3250  }
3251 
3252  return ovl ();
3253 }
3254 
3255 /*
3256 %!test
3257 %! f = str2func ("<");
3258 %! assert (class (f), "function_handle");
3259 %! assert (func2str (f), "lt");
3260 %! assert (f (1, 2), true);
3261 %! assert (f (2, 1), false);
3262 
3263 %!test
3264 %! f = str2func ("@(x) sin (x)");
3265 %! assert (func2str (f), "@(x) sin (x)");
3266 %! assert (f (0:3), sin (0:3));
3267 
3268 %!error <FCN_NAME must be a string> str2func ({"sin"})
3269 */
3270 
3271 /*
3272 %!function y = __testrecursionfunc (f, x, n)
3273 %! if (nargin < 3)
3274 %! n = 0;
3275 %! endif
3276 %! if (n > 2)
3277 %! y = f (x);
3278 %! else
3279 %! n++;
3280 %! y = __testrecursionfunc (@(x) f (2*x), x, n);
3281 %! endif
3282 %!endfunction
3283 %!
3284 %!assert (__testrecursionfunc (@(x) x, 1), 8)
3285 */
3286 
3287 DEFUN (is_function_handle, args, ,
3288  doc: /* -*- texinfo -*-
3289 @deftypefn {} {} is_function_handle (@var{x})
3290 Return true if @var{x} is a function handle.
3291 @seealso{isa, typeinfo, class, functions}
3292 @end deftypefn */)
3293 {
3294  if (args.length () != 1)
3295  print_usage ();
3296 
3297  return ovl (args(0).is_function_handle ());
3298 }
3299 
3300 /*
3301 %!shared fh
3302 %! fh = @(x) x;
3303 
3304 %!assert (is_function_handle (fh))
3305 %!assert (! is_function_handle ({fh}))
3306 %!assert (! is_function_handle (1))
3307 
3308 %!error is_function_handle ()
3309 %!error is_function_handle (1, 2)
3310 */
3311 
3312 /*
3313 %!test
3314 %! f = @(t) eval ('2*t');
3315 %! assert (f (21), 42);
3316 */
3317 
3318 /*
3319 %!test <*58389>
3320 %! s = "x";
3321 %! a.(s) = [e, pi];
3322 %! f = @(x) a.(s)(x);
3323 %! assert (f(1), e);
3324 %! assert (f(2), pi);
3325 %! assert (f([2,1]), [pi, e]);
3326 */
3327 
3328 /*
3329 %!function r = __f (g, i)
3330 %! r = g(i);
3331 %!endfunction
3332 %!test
3333 %! x = [1,2;3,4];
3334 %! assert (__f (@(i) x(:,i), 1), [1;3]);
3335 */
void swap_bytes< 4 >(void *ptr)
Definition: byte-swap.h:63
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:377
Definition: Cell.h:43
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
void add_method(T *obj, void(T::*method)(Params...), Args &&... args)
octave_value_list call(int nargout, const octave_value_list &args)
bool save_binary(std::ostream &os, bool save_as_floats)
void print_raw(std::ostream &, bool pr_as_read_syntax, int current_print_indent_level) const
octave_value fcn_val(void)
octave_user_function * user_function_value(bool=false)
bool save_ascii(std::ostream &os)
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
bool print_as_scalar(void) const
octave_function * function_value(bool=false)
static const std::string anonymous
anonymous_fcn_handle(const std::string &name="")
std::string type(void) const
anonymous_fcn_handle * clone(void) const
bool parse(const std::string &fcn_text)
friend bool is_equal_to(const anonymous_fcn_handle &fh1, const anonymous_fcn_handle &fh2)
anonymous_fcn_handle(const anonymous_fcn_handle &)=default
octave_scalar_map info(void)
bool load_binary(std::istream &is, bool swap, mach_info::float_format fmt)
bool load_hdf5(octave_hdf5_id &group_hid, octave_hdf5_id &space_hid, octave_hdf5_id &type_hid)
stack_frame::local_vars_map m_local_vars
octave_value workspace(void) const
~anonymous_fcn_handle(void)=default
bool load_ascii(std::istream &is)
octave_value convert_to_str_internal(bool pad, bool force, char type) const
void warn_save(const char *file_type) const
octave_value_list subsref(const std::string &type, const std::list< octave_value_list > &idx, int nargout)
virtual octave_value_list call(int nargout, const octave_value_list &args)=0
std::string fcn_name(void) const
Definition: ov-fcn-handle.h:79
virtual bool save_binary(std::ostream &os, bool save_as_floats)
base_fcn_handle(const std::string &name="", const std::string &file="")
Definition: ov-fcn-handle.h:54
std::string file(void) const
Definition: ov-fcn-handle.h:81
virtual bool load_hdf5(octave_hdf5_id &group_hid, octave_hdf5_id &space_hid, octave_hdf5_id &type_hid)
virtual void print_raw(std::ostream &, bool, int) const
virtual std::string type(void) const =0
virtual bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
virtual bool load_binary(std::istream &is, bool swap, mach_info::float_format fmt)
void unimplemented(const char *op, const char *fmt) const
virtual bool load_ascii(std::istream &is)
void warn_load(const char *file_type) const
virtual bool save_ascii(std::ostream &os)
size_t length(void) const
Definition: base-list.h:53
elt_type & front(void)
Definition: base-list.h:79
class_simple_fcn_handle(const std::string &name, const std::string &file, const std::string &)
std::string type(void) const
bool save_binary(std::ostream &os, bool save_as_floats)
std::string dispatch_class(void) const
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
friend bool is_equal_to(const class_simple_fcn_handle &fh1, const class_simple_fcn_handle &fh2)
octave_scalar_map info(void)
bool load_binary(std::istream &is, bool swap, mach_info::float_format fmt)
octave_function * function_value(bool=false)
octave_user_function * user_function_value(bool=false)
void print_raw(std::ostream &, bool pr_as_read_syntax, int current_print_indent_level) const
bool save_ascii(std::ostream &os)
class_simple_fcn_handle * clone(void) const
octave_value_list call(int nargout, const octave_value_list &args)
class_simple_fcn_handle(const class_simple_fcn_handle &)=default
bool load_hdf5(octave_hdf5_id &group_hid, octave_hdf5_id &space_hid, octave_hdf5_id &type_hid)
bool load_ascii(std::istream &is)
~class_simple_fcn_handle(void)=default
octave_scalar_map info(void)
std::string type(void) const
internal_fcn_handle * clone(void) const
octave_function * function_value(bool=false)
octave_user_function * user_function_value(bool=false)
internal_fcn_handle(const internal_fcn_handle &)=default
~internal_fcn_handle(void)=default
octave_value fcn_val(void)
octave_value_list call(int nargout, const octave_value_list &args)
friend bool is_equal_to(const internal_fcn_handle &fh1, const internal_fcn_handle &fh2)
bool is_internal(void) const
internal_fcn_handle(const octave_value &fcn)
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_value varval(const std::string &name) const
octave_value_list eval_string(const std::string &eval_str, bool silent, int &parse_status, int nargout)
symbol_table & get_symbol_table(void)
Definition: interpreter.h:258
tree_evaluator & get_evaluator(void)
~invalid_fcn_handle(void)=default
octave_value_list call(int nargout, const octave_value_list &args)
std::string type(void) const
invalid_fcn_handle * clone(void) const
invalid_fcn_handle(const invalid_fcn_handle &)=default
friend bool is_equal_to(const nested_fcn_handle &fh1, const nested_fcn_handle &fh2)
~nested_fcn_handle(void)=default
nested_fcn_handle(const std::string &name="", const std::string &file="", const std::string &="")
bool is_nested(void) const
octave_value fcn_val(void)
nested_fcn_handle(const nested_fcn_handle &)=default
nested_fcn_handle * clone(void) const
octave_value_list call(int nargout, const octave_value_list &args)
std::string type(void) const
bool load_binary(std::istream &is, bool swap, mach_info::float_format fmt)
bool load_ascii(std::istream &is)
bool save_ascii(std::ostream &os)
octave_value workspace(void) const
void print_raw(std::ostream &, bool pr_as_read_syntax, int current_print_indent_level) const
bool save_binary(std::ostream &os, bool save_as_floats)
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
octave_function * function_value(bool=false)
octave_scalar_map info(void)
bool load_hdf5(octave_hdf5_id &group_hid, octave_hdf5_id &space_hid, octave_hdf5_id &type_hid)
octave_user_function * user_function_value(bool=false)
std::shared_ptr< stack_frame > m_closure_frames
octave_user_function * user_function_value(bool=false)
octave_function * function_value(bool=false)
friend bool is_equal_to(const scoped_fcn_handle &fh1, const scoped_fcn_handle &fh2)
bool save_ascii(std::ostream &os)
~scoped_fcn_handle(void)=default
std::string type(void) const
bool load_ascii(std::istream &is)
bool is_scoped(void) const
bool load_hdf5(octave_hdf5_id &group_hid, octave_hdf5_id &space_hid, octave_hdf5_id &type_hid)
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
scoped_fcn_handle(const std::string &name="", const std::string &file="", const std::string &="")
scoped_fcn_handle(const scoped_fcn_handle &)=default
octave_scalar_map info(void)
std::list< std::string > m_parentage
octave_value_list call(int nargout, const octave_value_list &args)
void print_raw(std::ostream &, bool pr_as_read_syntax, int current_print_indent_level) const
octave_value fcn_val(void)
bool load_binary(std::istream &is, bool swap, mach_info::float_format fmt)
scoped_fcn_handle * clone(void) const
bool save_binary(std::ostream &os, bool save_as_floats)
friend bool is_equal_to(const simple_fcn_handle &fh1, const simple_fcn_handle &fh2)
void print_raw(std::ostream &os, bool pr_as_read_syntax, int current_print_indent_level) const
simple_fcn_handle * clone(void) const
octave_scalar_map info(void)
simple_fcn_handle(const simple_fcn_handle &)=default
bool is_simple(void) const
simple_fcn_handle(const octave_value &fcn, const std::string &name)
bool save_ascii(std::ostream &os)
bool load_hdf5(octave_hdf5_id &group_hid, octave_hdf5_id &space_hid, octave_hdf5_id &type_hid)
std::string type(void) const
simple_fcn_handle(const std::string &name="", const std::string &file="", const std::string &="")
octave_value_list call(int nargout, const octave_value_list &args)
bool save_binary(std::ostream &os, bool save_as_floats)
octave_function * function_value(bool)
octave_user_function * user_function_value(bool)
bool save_hdf5(octave_hdf5_id loc_hid, const char *name, bool save_as_floats)
octave_value fcn_val(void)
bool load_ascii(std::istream &is)
bool load_binary(std::istream &is, bool swap, mach_info::float_format fmt)
~simple_fcn_handle(void)=default
std::map< std::string, octave_value > local_vars_map
Definition: stack-frame.h:112
void cache_name(const std::string &name)
Definition: symscope.h:584
octave_value find_user_function(const std::string &name)
Definition: symtab.cc:288
octave_value find_function(const std::string &name, const symbol_scope &search_scope=symbol_scope())
Definition: symtab.cc:249
octave_value find_private_function(const std::string &dir_name, const std::string &name)
Definition: symtab.cc:99
octave_value make_fcn_handle(const std::string &nm)
Definition: pt-eval.cc:1011
void pop_stack_frame(void)
Definition: pt-eval.cc:1860
void pop_scope(void)
Definition: pt-eval.cc:2035
void set_dispatch_class(const std::string &class_name)
Definition: pt-eval.cc:1942
void push_dummy_scope(const std::string &name)
Definition: pt-eval.cc:2028
void push_stack_frame(const symbol_scope &scope)
Definition: pt-eval.cc:1833
void accept(tree_walker &tw)
Definition: pt-misc.h:102
void print_fcn_handle_body(tree_expression *)
Definition: pt-pr-code.cc:1123
bool is_expression(void) const
Definition: pt-stmt.h:80
tree_expression * expression(void)
Definition: pt-stmt.h:101
int current_print_indent_level(void) const
Definition: ov-base.h:847
void newline(std::ostream &os) const
Definition: ov-base.cc:1321
void warn_load(const char *type) const
Definition: ov-base.cc:1090
bool load_ascii(std::istream &is)
Definition: ov-cell.cc:791
Array< std::string > cellstr_value(void) const
Definition: ov-cell.cc:629
bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format fmt)
Definition: ov-cell.cc:923
bool iscellstr(void) const
Definition: ov-cell.cc:424
static const std::string anonymous
std::string fcn_name(void) const
void print_raw(std::ostream &os, bool pr_as_read_syntax=false) const
octave_scalar_map info(void)
bool is_simple(void) const
std::shared_ptr< octave::base_fcn_handle > m_rep
bool load_hdf5(octave_hdf5_id loc_id, const char *name)
bool is_internal(void) const
bool load_ascii(std::istream &is)
bool is_class_simple(void) const
octave::base_fcn_handle * get_rep(void) const
octave_value fcn_val(void)
bool is_anonymous(void) const
dim_vector dims(void) const
bool is_scoped(void) const
bool save_binary(std::ostream &os, bool save_as_floats)
bool save_ascii(std::ostream &os)
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
bool is_nested(void) const
bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format fmt)
void print(std::ostream &os, bool pr_as_read_syntax=false)
std::string dispatch_class(void) const
Definition: ov-fcn.h:151
virtual std::string fcn_file_name(void) const
Definition: ov-fcn.h:78
bool is_class_method(const std::string &cname="") const
Definition: ov-fcn.h:118
void assign(const std::string &k, const octave_value &val)
Definition: oct-map.h:238
std::string fcn_file_name(void) const
Definition: ov-usr-fcn.h:110
octave::symbol_scope scope(void)
Definition: ov-usr-fcn.h:98
octave_value_list execute(octave::tree_evaluator &tw, int nargout=0, const octave_value_list &args=octave_value_list())
Definition: ov-usr-fcn.cc:493
octave_value find_subfunction(const std::string &subfuns) const
Definition: ov-usr-fcn.cc:419
octave_idx_type length(void) const
Definition: ovl.h:113
octave_value_list & prepend(const octave_value &val)
Definition: ovl.cc:80
bool is_function(void) const
Definition: ov.h:730
bool is_classdef_object(void) const
Definition: ov.h:611
bool is_package(void) const
Definition: ov.h:617
octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition: ov.h:449
octave_user_function * user_function_value(bool silent=false) const
bool is_cs_list(void) const
Definition: ov.h:626
bool is_copy_of(const octave_value &val) const
Definition: ov.h:1294
bool save_binary(std::ostream &os, bool save_as_floats)
Definition: ov.h:1303
bool is_defined(void) const
Definition: ov.h:551
bool save_ascii(std::ostream &os)
Definition: ov.h:1299
bool is_classdef_meta(void) const
Definition: ov.h:608
octave_function * function_value(bool silent=false) const
octave_fcn_handle * fcn_handle_value(bool silent=false) const
bool is_undefined(void) const
Definition: ov.h:554
const octave_hdf5_id octave_H5P_DEFAULT
const octave_hdf5_id octave_H5E_DEFAULT
const octave_hdf5_id octave_H5S_ALL
OCTINTERP_API void print_usage(void)
Definition: defun.cc:53
#define DEFMETHOD(name, interp_name, args_name, nargout_name, doc)
Macro to define a builtin method.
Definition: defun.h:138
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void warning(const char *fmt,...)
Definition: error.cc:1050
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:1065
void error(const char *fmt,...)
Definition: error.cc:968
#define panic_impossible()
Definition: error.h:380
QString name
std::string read_until_newline(std::istream &is, bool keep_newline)
void skip_preceeding_newline(std::istream &is)
octave_hdf5_err hdf5_h5g_iterate(octave_hdf5_id loc_id, const char *name, int *idx, void *operator_data)
Definition: ls-hdf5.cc:1034
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:1380
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:287
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:363
T octave_idx_type m
Definition: mx-inlines.cc:773
std::string octave_exec_home(void)
Definition: defaults.cc:164
std::string dirname(const std::string &path)
Definition: file-ops.cc:363
std::string dir_sep_chars(void)
Definition: file-ops.cc:252
static double f(double k, double l_nu, double c_pm)
Definition: randpoisson.cc:118
interpreter & __get_interpreter__(const std::string &who)
static void err_invalid_fcn_handle(const std::string &name)
tree_evaluator & __get_evaluator__(const std::string &who)
symbol_table & __get_symbol_table__(const std::string &who)
bool is_equal_to(const anonymous_fcn_handle &fh1, const anonymous_fcn_handle &fh2)
static octave_value make_fcn_handle(const octave_value &fcn, const std::string &meth_name, const std::string &class_name)
Definition: cdef-class.cc:66
int64_t octave_hdf5_id
#define H5T_NATIVE_IDX
Definition: oct-hdf5.h:42
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
#define DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(t, n, c)
Definition: ov-base.h:180
bool is_equal_to(const octave_fcn_handle &fh1, const octave_fcn_handle &fh2)
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
void octave_print_internal(std::ostream &os, const float_display_format &fmt, bool d, bool pr_as_read_syntax)
Definition: pr-output.cc:1762
octave_value tc
Definition: ls-hdf5.h:114
std::string name
Definition: ls-hdf5.h:108
F77_RET_T len
Definition: xerbla.cc:61