GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ov-fcn-inline.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2004-2018 David Bateman
4 
5 This file is part of Octave.
6 
7 Octave is free software: you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <https://www.gnu.org/licenses/>.
20 
21 In addition to the terms of the GPL, you are permitted to link
22 this program with any Open Source program, as defined by the
23 Open Source Initiative (www.opensource.org)
24 
25 */
26 
27 #if defined (HAVE_CONFIG_H)
28 # include "config.h"
29 #endif
30 
31 #include <istream>
32 #include <iostream>
33 #include <sstream>
34 #include <vector>
35 
36 #include "oct-locbuf.h"
37 
38 #include "call-stack.h"
39 #include "defun.h"
40 #include "error.h"
41 #include "errwarn.h"
42 #include "interpreter-private.h"
43 #include "interpreter.h"
44 #include "oct-hdf5.h"
45 #include "oct-map.h"
46 #include "ov-base.h"
47 #include "ov-fcn-inline.h"
48 #include "ov-usr-fcn.h"
49 #include "parse.h"
50 #include "pr-output.h"
51 #include "variables.h"
52 
53 #include "byte-swap.h"
54 #include "ls-ascii-helper.h"
55 #include "ls-oct-text.h"
56 #include "ls-hdf5.h"
57 #include "ls-utils.h"
58 
59 
61  "inline function",
62  "function_handle");
63 
65  const string_vector& a,
66  const std::string& n)
67  : octave_fcn_handle (n), iftext (f), ifargs (a)
68 {
69  // Form a string representing the function.
70 
71  std::ostringstream buf;
72 
73  buf << "@(";
74 
75  for (int i = 0; i < ifargs.numel (); i++)
76  {
77  if (i > 0)
78  buf << ", ";
79 
80  buf << ifargs(i);
81  }
82 
83  buf << ") " << iftext;
84 
85  int parse_status;
86  octave_value anon_fcn_handle = octave::eval_string (buf.str (), true, parse_status);
87 
88  if (parse_status == 0)
89  {
90  octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
91 
92  if (fh)
93  {
94  fcn = fh->fcn_val ();
95 
97 
98  if (uf)
99  {
101  = octave::__get_call_stack__ ("octave_fcn_inline");
102 
103  octave_function *curr_fcn = cs.current ();
104 
105  if (curr_fcn)
106  {
107  octave::symbol_scope parent_scope
108  = curr_fcn->parent_fcn_scope ();
109 
110  if (! parent_scope)
111  parent_scope = curr_fcn->scope ();
112 
113  uf->stash_parent_fcn_scope (parent_scope);
114  }
115  }
116  }
117  }
118 
119  if (fcn.is_undefined ())
120  error ("inline: unable to define function");
121 }
122 
123 // This function is supplied to allow a Matlab style class structure
124 // to be returned..
127 {
129 
130  m.assign ("version", 1.0);
131  m.assign ("isEmpty", 0.0);
132  m.assign ("expr", fcn_text ());
133 
134  string_vector args = fcn_arg_names ();
135 
136  m.assign ("numArgs", args.numel ());
137  m.assign ("args", args);
138 
139  std::ostringstream buf;
140 
141  for (int i = 0; i < args.numel (); i++)
142  buf << args(i) << " = INLINE_INPUTS_{" << i + 1 << "}; ";
143 
144  m.assign ("inputExpr", buf.str ());
145 
146  return m;
147 }
148 
149 bool
151 {
152  os << "# nargs: " << ifargs.numel () << "\n";
153  for (int i = 0; i < ifargs.numel (); i++)
154  os << ifargs(i) << "\n";
155  if (nm.length () < 1)
156  // Write an invalid value to flag empty fcn handle name.
157  os << "0\n";
158  else
159  os << nm << "\n";
160  os << iftext << "\n";
161  return true;
162 }
163 
164 bool
166 {
167  int nargs;
168  if (extract_keyword (is, "nargs", nargs, true))
169  {
170  ifargs.resize (nargs);
171  for (int i = 0; i < nargs; i++)
172  is >> ifargs(i);
173  is >> nm;
174  if (nm == "0")
175  nm = "";
176 
178 
179  std::string buf;
180 
181  if (is)
182  {
183 
184  // Get a line of text whitespace characters included,
185  // leaving newline in the stream.
186  buf = read_until_newline (is, true);
187  }
188 
189  iftext = buf;
190 
192  fcn = tmp.fcn;
193 
194  return true;
195  }
196  else
197  return false;
198 }
199 
200 bool
201 octave_fcn_inline::save_binary (std::ostream& os, bool&)
202 {
203  int32_t tmp = ifargs.numel ();
204  os.write (reinterpret_cast<char *> (&tmp), 4);
205  for (int i = 0; i < ifargs.numel (); i++)
206  {
207  tmp = ifargs(i).length ();
208  os.write (reinterpret_cast<char *> (&tmp), 4);
209  os.write (ifargs(i).c_str (), ifargs(i).length ());
210  }
211  tmp = nm.length ();
212  os.write (reinterpret_cast<char *> (&tmp), 4);
213  os.write (nm.c_str (), nm.length ());
214  tmp = iftext.length ();
215  os.write (reinterpret_cast<char *> (&tmp), 4);
216  os.write (iftext.c_str (), iftext.length ());
217  return true;
218 }
219 
220 bool
223 {
224  int32_t nargs;
225  if (! is.read (reinterpret_cast<char *> (&nargs), 4))
226  return false;
227  if (swap)
228  swap_bytes<4> (&nargs);
229 
230  if (nargs < 1)
231  return false;
232  else
233  {
234  int32_t tmp;
235  ifargs.resize (nargs);
236  for (int i = 0; i < nargs; i++)
237  {
238  if (! is.read (reinterpret_cast<char *> (&tmp), 4))
239  return false;
240  if (swap)
241  swap_bytes<4> (&tmp);
242 
243  OCTAVE_LOCAL_BUFFER (char, ctmp, tmp+1);
244  is.read (ctmp, tmp);
245  ifargs(i) = std::string (ctmp);
246 
247  if (! is)
248  return false;
249  }
250 
251  if (! is.read (reinterpret_cast<char *> (&tmp), 4))
252  return false;
253  if (swap)
254  swap_bytes<4> (&tmp);
255 
256  OCTAVE_LOCAL_BUFFER (char, ctmp1, tmp+1);
257  is.read (ctmp1, tmp);
258  nm = std::string (ctmp1);
259 
260  if (! is)
261  return false;
262 
263  if (! is.read (reinterpret_cast<char *> (&tmp), 4))
264  return false;
265  if (swap)
266  swap_bytes<4> (&tmp);
267 
268  OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1);
269  is.read (ctmp2, tmp);
270  iftext = std::string (ctmp2);
271 
272  if (! is)
273  return false;
274 
276  fcn = ftmp.fcn;
277  }
278  return true;
279 }
280 
281 bool
283  bool /* save_as_floats */)
284 {
285  bool retval = false;
286 
287 #if defined (HAVE_HDF5)
288 
289  hid_t group_hid = -1;
290 
291 #if defined (HAVE_HDF5_18)
292  group_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT,
294 #else
295  group_hid = H5Gcreate (loc_id, name, 0);
296 #endif
297  if (group_hid < 0) return false;
298 
299  size_t len = 0;
300  for (int i = 0; i < ifargs.numel (); i++)
301  if (len < ifargs(i).length ())
302  len = ifargs(i).length ();
303 
304  hid_t space_hid, data_hid, type_hid;
305  space_hid = data_hid = type_hid = -1;
306 
307  // FIXME: Is there a better way of saving string vectors,
308  // than a null padded matrix?
309 
310  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2);
311 
312  // Octave uses column-major, while HDF5 uses row-major ordering
313  hdims[1] = ifargs.numel ();
314  hdims[0] = len + 1;
315 
316  space_hid = H5Screate_simple (2, hdims, nullptr);
317  if (space_hid < 0)
318  {
319  H5Gclose (group_hid);
320  return false;
321  }
322 #if defined (HAVE_HDF5_18)
323  data_hid = H5Dcreate (group_hid, "args", H5T_NATIVE_CHAR, space_hid,
325 #else
326  data_hid = H5Dcreate (group_hid, "args", H5T_NATIVE_CHAR, space_hid,
328 #endif
329  if (data_hid < 0)
330  {
331  H5Sclose (space_hid);
332  H5Gclose (group_hid);
333  return false;
334  }
335 
336  OCTAVE_LOCAL_BUFFER (char, s, ifargs.numel () * (len + 1));
337 
338  // Save the args as a null teminated list
339  for (int i = 0; i < ifargs.numel (); i++)
340  {
341  const char *cptr = ifargs(i).c_str ();
342  for (size_t j = 0; j < ifargs(i).length (); j++)
343  s[i*(len+1)+j] = *cptr++;
344  s[ifargs(i).length ()] = '\0';
345  }
346 
347  retval = H5Dwrite (data_hid, H5T_NATIVE_CHAR, octave_H5S_ALL, octave_H5S_ALL,
348  octave_H5P_DEFAULT, s) >= 0;
349 
350  H5Dclose (data_hid);
351  H5Sclose (space_hid);
352 
353  if (! retval)
354  {
355  H5Gclose (group_hid);
356  return false;
357  }
358 
359  // attach the type of the variable
360  type_hid = H5Tcopy (H5T_C_S1);
361  H5Tset_size (type_hid, nm.length () + 1);
362  if (type_hid < 0)
363  {
364  H5Gclose (group_hid);
365  return false;
366  }
367 
368  hdims[0] = 0;
369  space_hid = H5Screate_simple (0 , hdims, nullptr);
370  if (space_hid < 0)
371  {
372  H5Tclose (type_hid);
373  H5Gclose (group_hid);
374  return false;
375  }
376 #if defined (HAVE_HDF5_18)
377  data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid,
379 #else
380  data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid,
382 #endif
383  if (data_hid < 0
384  || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
385  octave_H5P_DEFAULT, nm.c_str ()) < 0)
386  {
387  H5Sclose (space_hid);
388  H5Tclose (type_hid);
389  H5Gclose (group_hid);
390  return false;
391  }
392  H5Dclose (data_hid);
393 
394  // attach the type of the variable
395  H5Tset_size (type_hid, iftext.length () + 1);
396  if (type_hid < 0)
397  {
398  H5Gclose (group_hid);
399  return false;
400  }
401 
402 #if defined (HAVE_HDF5_18)
403  data_hid = H5Dcreate (group_hid, "iftext", type_hid, space_hid,
405 #else
406  data_hid = H5Dcreate (group_hid, "iftext", type_hid, space_hid,
408 #endif
409  if (data_hid < 0
410  || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
411  octave_H5P_DEFAULT, iftext.c_str ()) < 0)
412  {
413  H5Sclose (space_hid);
414  H5Tclose (type_hid);
415  H5Gclose (group_hid);
416  return false;
417  }
418 
419  H5Dclose (data_hid);
420  H5Sclose (space_hid);
421  H5Tclose (type_hid);
422  H5Gclose (group_hid);
423 
424 #else
425  octave_unused_parameter (loc_id);
426  octave_unused_parameter (name);
427 
428  warn_save ("hdf5");
429 #endif
430 
431  return retval;
432 }
433 
434 bool
436 {
437 #if defined (HAVE_HDF5)
438 
439  hid_t group_hid, data_hid, space_hid, type_hid, type_class_hid, st_id;
440  hsize_t rank;
441  int slen;
442 
443 #if defined (HAVE_HDF5_18)
444  group_hid = H5Gopen (loc_id, name, octave_H5P_DEFAULT);
445 #else
446  group_hid = H5Gopen (loc_id, name);
447 #endif
448  if (group_hid < 0) return false;
449 
450 #if defined (HAVE_HDF5_18)
451  data_hid = H5Dopen (group_hid, "args", octave_H5P_DEFAULT);
452 #else
453  data_hid = H5Dopen (group_hid, "args");
454 #endif
455  space_hid = H5Dget_space (data_hid);
456  rank = H5Sget_simple_extent_ndims (space_hid);
457 
458  if (rank != 2)
459  {
460  H5Dclose (data_hid);
461  H5Sclose (space_hid);
462  H5Gclose (group_hid);
463  return false;
464  }
465 
466  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
467  OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
468 
469  H5Sget_simple_extent_dims (space_hid, hdims, maxdims);
470 
471  ifargs.resize (hdims[1]);
472 
473  OCTAVE_LOCAL_BUFFER (char, s1, hdims[0] * hdims[1]);
474 
475  if (H5Dread (data_hid, H5T_NATIVE_UCHAR, octave_H5S_ALL, octave_H5S_ALL,
476  octave_H5P_DEFAULT, s1) < 0)
477  {
478  H5Dclose (data_hid);
479  H5Sclose (space_hid);
480  H5Gclose (group_hid);
481  return false;
482  }
483 
484  H5Dclose (data_hid);
485  H5Sclose (space_hid);
486 
487  for (size_t i = 0; i < hdims[1]; i++)
488  ifargs(i) = std::string (s1 + i*hdims[0]);
489 
490 #if defined (HAVE_HDF5_18)
491  data_hid = H5Dopen (group_hid, "nm", octave_H5P_DEFAULT);
492 #else
493  data_hid = H5Dopen (group_hid, "nm");
494 #endif
495 
496  if (data_hid < 0)
497  {
498  H5Gclose (group_hid);
499  return false;
500  }
501 
502  type_hid = H5Dget_type (data_hid);
503  type_class_hid = H5Tget_class (type_hid);
504 
505  if (type_class_hid != H5T_STRING)
506  {
507  H5Tclose (type_hid);
508  H5Dclose (data_hid);
509  H5Gclose (group_hid);
510  return false;
511  }
512 
513  space_hid = H5Dget_space (data_hid);
514  rank = H5Sget_simple_extent_ndims (space_hid);
515 
516  if (rank != 0)
517  {
518  H5Sclose (space_hid);
519  H5Tclose (type_hid);
520  H5Dclose (data_hid);
521  H5Gclose (group_hid);
522  return false;
523  }
524 
525  slen = H5Tget_size (type_hid);
526  if (slen < 0)
527  {
528  H5Sclose (space_hid);
529  H5Tclose (type_hid);
530  H5Dclose (data_hid);
531  H5Gclose (group_hid);
532  return false;
533  }
534 
535  OCTAVE_LOCAL_BUFFER (char, nm_tmp, slen);
536 
537  // create datatype for (null-terminated) string to read into:
538  st_id = H5Tcopy (H5T_C_S1);
539  H5Tset_size (st_id, slen);
540 
541  if (H5Dread (data_hid, st_id, octave_H5S_ALL, octave_H5S_ALL,
542  octave_H5P_DEFAULT, nm_tmp) < 0)
543  {
544  H5Sclose (space_hid);
545  H5Tclose (type_hid);
546  H5Gclose (group_hid);
547  return false;
548  }
549  H5Tclose (st_id);
550  H5Dclose (data_hid);
551  nm = nm_tmp;
552 
553 #if defined (HAVE_HDF5_18)
554  data_hid = H5Dopen (group_hid, "iftext", octave_H5P_DEFAULT);
555 #else
556  data_hid = H5Dopen (group_hid, "iftext");
557 #endif
558 
559  if (data_hid < 0)
560  {
561  H5Gclose (group_hid);
562  return false;
563  }
564 
565  type_hid = H5Dget_type (data_hid);
566  type_class_hid = H5Tget_class (type_hid);
567 
568  if (type_class_hid != H5T_STRING)
569  {
570  H5Tclose (type_hid);
571  H5Dclose (data_hid);
572  H5Gclose (group_hid);
573  return false;
574  }
575 
576  space_hid = H5Dget_space (data_hid);
577  rank = H5Sget_simple_extent_ndims (space_hid);
578 
579  if (rank != 0)
580  {
581  H5Sclose (space_hid);
582  H5Tclose (type_hid);
583  H5Dclose (data_hid);
584  H5Gclose (group_hid);
585  return false;
586  }
587 
588  slen = H5Tget_size (type_hid);
589  if (slen < 0)
590  {
591  H5Sclose (space_hid);
592  H5Tclose (type_hid);
593  H5Dclose (data_hid);
594  H5Gclose (group_hid);
595  return false;
596  }
597 
598  OCTAVE_LOCAL_BUFFER (char, iftext_tmp, slen);
599 
600  // create datatype for (null-terminated) string to read into:
601  st_id = H5Tcopy (H5T_C_S1);
602  H5Tset_size (st_id, slen);
603 
604  if (H5Dread (data_hid, st_id, octave_H5S_ALL, octave_H5S_ALL,
605  octave_H5P_DEFAULT, iftext_tmp) < 0)
606  {
607  H5Sclose (space_hid);
608  H5Tclose (type_hid);
609  H5Gclose (group_hid);
610  return false;
611  }
612  H5Tclose (st_id);
613  H5Dclose (data_hid);
614  iftext = iftext_tmp;
615 
617  fcn = ftmp.fcn;
618 
619  return true;
620 
621 #else
622  octave_unused_parameter (loc_id);
623  octave_unused_parameter (name);
624 
625  warn_load ("hdf5");
626 
627  return false;
628 #endif
629 }
630 
631 void
632 octave_fcn_inline::print (std::ostream& os, bool pr_as_read_syntax)
633 {
634  print_raw (os, pr_as_read_syntax);
635  newline (os);
636 }
637 
638 void
639 octave_fcn_inline::print_raw (std::ostream& os, bool pr_as_read_syntax) const
640 {
641  std::ostringstream buf;
642 
643  if (nm.empty ())
644  buf << "f(";
645  else
646  buf << nm << '(';
647 
648  for (int i = 0; i < ifargs.numel (); i++)
649  {
650  if (i)
651  buf << ", ";
652 
653  buf << ifargs(i);
654  }
655 
656  buf << ") = " << iftext;
657 
658  octave_print_internal (os, buf.str (), pr_as_read_syntax,
660 }
661 
664 {
665  return octave_value (fcn_text (), type);
666 }
667 
668 DEFUNX ("inline", Finline, args, ,
669  doc: /* -*- texinfo -*-
670 @deftypefn {} {} inline (@var{str})
671 @deftypefnx {} {} inline (@var{str}, @var{arg1}, @dots{})
672 @deftypefnx {} {} inline (@var{str}, @var{n})
673 Create an inline function from the character string @var{str}.
674 
675 If called with a single argument, the arguments of the generated function
676 are extracted from the function itself. The generated function arguments
677 will then be in alphabetical order. It should be noted that i and j are
678 ignored as arguments due to the ambiguity between their use as a variable or
679 their use as an built-in constant. All arguments followed by a parenthesis
680 are considered to be functions. If no arguments are found, a function
681 taking a single argument named @code{x} will be created.
682 
683 If the second and subsequent arguments are character strings, they are the
684 names of the arguments of the function.
685 
686 If the second argument is an integer @var{n}, the arguments are
687 @qcode{"x"}, @qcode{"P1"}, @dots{}, @qcode{"P@var{N}"}.
688 
689 Programming Note: The use of @code{inline} is discouraged and it may be
690 removed from a future version of Octave. The preferred way to create
691 functions from strings is through the use of anonymous functions
692 (@pxref{Anonymous Functions}) or @code{str2func}.
693 @seealso{argnames, formula, vectorize, str2func}
694 @end deftypefn */)
695 {
696  int nargin = args.length ();
697 
698  if (nargin == 0)
699  print_usage ();
700 
701  std::string fun = args(0).xstring_value ("inline: STR argument must be a string");
702 
703  string_vector fargs;
704 
705  if (nargin == 1)
706  {
707  bool is_arg = false;
708  bool in_string = false;
709  std::string tmp_arg;
710  size_t i = 0;
711  size_t fun_length = fun.length ();
712 
713  while (i < fun_length)
714  {
715  bool terminate_arg = false;
716  char c = fun[i++];
717 
718  if (in_string)
719  {
720  if (c == '\'' || c == '\"')
721  in_string = false;
722  }
723  else if (c == '\'' || c == '\"')
724  {
725  in_string = true;
726  if (is_arg)
727  terminate_arg = true;
728  }
729  else if (! isalpha (c) && c != '_')
730  if (! is_arg)
731  continue;
732  else if (isdigit (c))
733  tmp_arg.append (1, c);
734  else
735  {
736  // Before we do anything remove trailing whitespaces.
737  while (i < fun_length && isspace (c))
738  c = fun[i++];
739 
740  // Do we have a variable or a function?
741  if (c != '(')
742  terminate_arg = true;
743  else
744  {
745  tmp_arg = "";
746  is_arg = false;
747  }
748  }
749  else if (! is_arg)
750  {
751  if (c == 'e' || c == 'E')
752  {
753  // possible number in exponent form, not arg
754  if (isdigit (fun[i]) || fun[i] == '-' || fun[i] == '+')
755  continue;
756  }
757  is_arg = true;
758  tmp_arg.append (1, c);
759  }
760  else
761  {
762  tmp_arg.append (1, c);
763  }
764 
765  if (terminate_arg || (i == fun_length && is_arg))
766  {
767  bool have_arg = false;
768 
769  for (int j = 0; j < fargs.numel (); j++)
770  if (tmp_arg == fargs (j))
771  {
772  have_arg = true;
773  break;
774  }
775 
776  if (! have_arg && tmp_arg != "i" && tmp_arg != "j"
777  && tmp_arg != "NaN" && tmp_arg != "nan"
778  && tmp_arg != "Inf" && tmp_arg != "inf"
779  && tmp_arg != "NA" && tmp_arg != "pi"
780  && tmp_arg != "e" && tmp_arg != "eps")
781  fargs.append (tmp_arg);
782 
783  tmp_arg = "";
784  is_arg = false;
785  }
786  }
787 
788  // Sort the arguments into ASCII order.
789  fargs.sort ();
790 
791  if (fargs.isempty ())
792  fargs.append (std::string ("x"));
793 
794  }
795  else if (nargin == 2 && args(1).isnumeric ())
796  {
797  if (! args(1).is_scalar_type ())
798  error ("inline: N must be an integer");
799 
800  int n = args(1).int_value ("inline: N must be an integer");
801 
802  if (n < 0)
803  error ("inline: N must be a positive integer or zero");
804 
805  fargs.resize (n+1);
806 
807  fargs(0) = "x";
808 
809  for (int i = 1; i < n+1; i++)
810  {
811  std::ostringstream buf;
812  buf << 'P' << i;
813  fargs(i) = buf.str ();
814  }
815  }
816  else
817  {
818  fargs.resize (nargin - 1);
819 
820  for (int i = 1; i < nargin; i++)
821  {
822  std::string s = args(i).xstring_value ("inline: additional arguments must be strings");
823  fargs(i-1) = s;
824  }
825  }
826 
827  return ovl (new octave_fcn_inline (fun, fargs));
828 }
829 
830 /*
831 %!shared fn
832 %! fn = inline ("x.^2 + 1");
833 %!assert (feval (fn, 6), 37)
834 %!assert (fn (6), 37)
835 %!assert (feval (inline ("sum (x(:))"), [1 2; 3 4]), 10)
836 %!assert (feval (inline ("sqrt (x^2 + y^2)", "x", "y"), 3, 4), 5)
837 %!assert (feval (inline ("exp (P1*x) + P2", 3), 3, 4, 5), exp(3*4) + 5)
838 
839 ## Test input validation
840 %!error inline ()
841 %!error <STR argument must be a string> inline (1)
842 %!error <N must be an integer> inline ("2", ones (2,2))
843 %!error <N must be a positive integer> inline ("2", -1)
844 %!error <additional arguments must be strings> inline ("2", "x", -1, "y")
845 */
846 
847 DEFUN (formula, args, ,
848  doc: /* -*- texinfo -*-
849 @deftypefn {} {} formula (@var{fun})
850 Return a character string representing the inline function @var{fun}.
851 
852 Note that @code{char (@var{fun})} is equivalent to
853 @code{formula (@var{fun})}.
854 @seealso{char, argnames, inline, vectorize}
855 @end deftypefn */)
856 {
857  if (args.length () != 1)
858  print_usage ();
859 
860  octave_fcn_inline *fn = args(0).fcn_inline_value (true);
861 
862  if (! fn)
863  error ("formula: FUN must be an inline function");
864 
865  return ovl (fn->fcn_text ());
866 }
867 
868 /*
869 %!assert (formula (fn), "x.^2 + 1")
870 %!assert (formula (fn), char (fn))
871 
872 ## Test input validation
873 %!error formula ()
874 %!error formula (1, 2)
875 %!error <FUN must be an inline function> formula (1)
876 */
877 
878 DEFUN (argnames, args, ,
879  doc: /* -*- texinfo -*-
880 @deftypefn {} {} argnames (@var{fun})
881 Return a cell array of character strings containing the names of the
882 arguments of the inline function @var{fun}.
883 @seealso{inline, formula, vectorize}
884 @end deftypefn */)
885 {
886  if (args.length () != 1)
887  print_usage ();
888 
889  octave_fcn_inline *fn = args(0).fcn_inline_value (true);
890 
891  if (! fn)
892  error ("argnames: FUN must be an inline function");
893 
894  string_vector t1 = fn->fcn_arg_names ();
895 
896  Cell t2 (dim_vector (t1.numel (), 1));
897 
898  for (int i = 0; i < t1.numel (); i++)
899  t2(i) = t1(i);
900 
901  return ovl (t2);
902 }
903 
904 /*
905 %!assert (argnames (fn), {"x"})
906 %!assert (argnames (inline ("1e-3*y + 2e4*z")), {"y"; "z"})
907 %!assert (argnames (inline ("2", 2)), {"x"; "P1"; "P2"})
908 
909 ## Test input validation
910 %!error argnames ()
911 %!error argnames (1, 2)
912 %!error <FUN must be an inline function> argnames (1)
913 */
914 
915 DEFUN (vectorize, args, ,
916  doc: /* -*- texinfo -*-
917 @deftypefn {} {} vectorize (@var{fun})
918 Create a vectorized version of the inline function @var{fun} by replacing
919 all occurrences of @code{*}, @code{/}, etc., with @code{.*}, @code{./}, etc.
920 
921 This may be useful, for example, when using inline functions with numerical
922 integration or optimization where a vector-valued function is expected.
923 
924 @example
925 @group
926 fcn = vectorize (inline ("x^2 - 1"))
927  @result{} fcn = f(x) = x.^2 - 1
928 quadv (fcn, 0, 3)
929  @result{} 6
930 @end group
931 @end example
932 @seealso{inline, formula, argnames}
933 @end deftypefn */)
934 {
935  if (args.length () != 1)
936  print_usage ();
937 
938  std::string old_func;
939  octave_fcn_inline *old = nullptr;
940  bool func_is_string = true;
941 
942  if (args(0).is_string ())
943  old_func = args(0).string_value ();
944  else
945  {
946  func_is_string = false;
947 
948  old = args(0).fcn_inline_value (true);
949  if (! old)
950  error ("vectorize: FUN must be a string or inline function");
951 
952  old_func = old->fcn_text ();
953  }
954 
955  size_t len = old_func.length ();
956  std::string new_func;
957  new_func.reserve (len + 10);
958 
959  size_t i = 0;
960  while (i < len)
961  {
962  char t1 = old_func[i];
963 
964  if (t1 == '*' || t1 == '/' || t1 == '\\' || t1 == '^')
965  {
966  if (i && old_func[i-1] != '.')
967  new_func.push_back ('.');
968 
969  // Special case for ** operator.
970  if (t1 == '*' && i < (len - 1) && old_func[i+1] == '*')
971  {
972  new_func.push_back ('*');
973  i++;
974  }
975  }
976  new_func.push_back (t1);
977  i++;
978  }
979 
980  if (func_is_string)
981  return ovl (new_func);
982  else
983  return ovl (new octave_fcn_inline (new_func, old->fcn_arg_names ()));
984 }
985 
986 /*
987 %!assert (char (vectorize (fn)), "x.^2 + 1")
988 %!assert (char (vectorize (inline ("1e-3*y + 2e4*z"))), "1e-3.*y + 2e4.*z")
989 %!assert (char (vectorize (inline ("2**x^5"))), "2.**x.^5")
990 %!assert (vectorize ("x.^2 + 1"), "x.^2 + 1")
991 %!assert (vectorize ("1e-3*y + 2e4*z"), "1e-3.*y + 2e4.*z")
992 %!assert (vectorize ("2**x^5"), "2.**x.^5")
993 
994 ## Test input validation
995 %!error vectorize ()
996 %!error vectorize (1, 2)
997 %!error <FUN must be a string or inline function> vectorize (1)
998 */
octave_idx_type write(const octave_value &data, octave_idx_type block_size, oct_data_conv::data_type output_type, octave_idx_type skip, mach_info::float_format flt_fmt)
Definition: oct-stream.cc:6704
octave_value fcn_val(void) const
OCTAVE_EXPORT octave_value_list Finline(const octave_value_list &args, int) the arguments of the generated function are extracted from the function itself. The generated function arguments will then be in alphabetical order. It should be noted that i and j are ignored as arguments due to the ambiguity between their use as a variable or their use as an built-in const ant. All arguments followed by a parenthesis are considered to be functions. If no arguments are found
virtual octave::symbol_scope scope(void)
Definition: ov-fcn.h:88
std::string read_until_newline(std::istream &is, bool keep_newline)
Definition: Cell.h:37
std::string fcn_text(void) const
Definition: ov-fcn-inline.h:65
void print_raw(std::ostream &os, bool pr_as_read_syntax=false) const
bool isempty(void) const
Definition: Array.h:565
OCTINTERP_API void print_usage(void)
Definition: defun.cc:54
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
int current_print_indent_level(void) const
Definition: ov-base.h:849
F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE * f
const octave_hdf5_id octave_H5S_ALL
void newline(std::ostream &os) const
Definition: ov-base.cc:1328
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:53
void error(const char *fmt,...)
Definition: error.cc:578
bool save_binary(std::ostream &os, bool &save_as_floats)
#define DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(t, n, c)
Definition: ov-base.h:180
void skip_preceeding_newline(std::istream &is)
nd example oindent opens the file binary numeric values will be read assuming they are stored in IEEE format with the least significant bit and then converted to the native representation Opening a file that is already open simply opens it again and returns a separate file id It is not an error to open a file several though writing to the same file through several different file ids may produce unexpected results The possible values of text mode reading and writing automatically converts linefeeds to the appropriate line end character for the you may append a you must also open the file in binary mode The parameter conversions are currently only supported for and permissions will be set to and then everything is written in a single operation This is very efficient and improves performance c
Definition: file-io.cc:587
s
Definition: file-io.cc:2729
bool load_ascii(std::istream &is)
void resize(octave_idx_type n, const std::string &rfv="")
Definition: str-vec.h:97
OCTAVE_EXPORT octave_value_list isnumeric
Definition: data.cc:3157
void print(std::ostream &os, bool pr_as_read_syntax=false)
void warn_load(const char *type) const
Definition: ov-base.cc:1097
octave_map map_value(void) const
calling an anonymous function involves an overhead quite comparable to the overhead of an m file function Passing a handle to a built in function is because the interpreter is not involved in the internal loop For a
Definition: cellfun.cc:400
bool swap
Definition: load-save.cc:738
octave::call_stack & cs
Definition: ov-class.cc:1752
string_vector fcn_arg_names(void) const
Definition: ov-fcn-inline.h:67
void octave_print_internal(std::ostream &os, const float_display_format &fmt, bool d, bool pr_as_read_syntax)
Definition: pr-output.cc:1780
nd deftypefn *std::string name
Definition: sysdep.cc:647
void swap_bytes< 4 >(void *ptr)
Definition: byte-swap.h:60
std::string extract_keyword(std::istream &is, const char *keyword, const bool next_only)
Definition: ls-oct-text.cc:82
OCTINTERP_API octave_value_list eval_string(const std::string &, bool silent, int &parse_status, int nargout)
string_vector ifargs
Definition: ov-fcn-inline.h:98
string_vector & append(const std::string &s)
Definition: str-vec.cc:107
bool load_hdf5(octave_hdf5_id loc_id, const char *name)
#define DEFUNX(name, fname, args_name, nargout_name, doc)
Macro to define a builtin function with certain internal name.
Definition: defun.h:82
double tmp
Definition: data.cc:6252
octave_value retval
Definition: data.cc:6246
int64_t octave_hdf5_id
octave_user_function * user_function_value(bool silent=false) const
void warn_save(const char *type) const
Definition: ov-base.cc:1106
string_vector & sort(bool make_uniq=false)
Definition: str-vec.cc:74
idx type
Definition: ov.cc:3114
std::string iftext
Definition: ov-fcn-inline.h:95
friend class octave_value
Definition: ov-base.h:228
bool save_ascii(std::ostream &os)
octave_function * current(void) const
Definition: call-stack.h:97
octave_fcn_handle * fcn_handle_value(bool silent=false) const
bool is_undefined(void) const
Definition: ov.h:526
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).isinteger())
octave_value convert_to_str_internal(bool, bool, char) const
void assign(const std::string &k, const octave_value &val)
Definition: oct-map.h:227
call_stack & __get_call_stack__(const std::string &who)
octave_value fcn
void stash_parent_fcn_scope(const octave::symbol_scope &ps)
Definition: ov-usr-fcn.cc:362
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:41
args.length() nargin
Definition: file-io.cc:589
for i
Definition: data.cc:5264
const octave_hdf5_id octave_H5P_DEFAULT
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:366
write the output to stdout if nargout is
Definition: load-save.cc:1612
virtual octave::symbol_scope parent_fcn_scope(void) const
Definition: ov-fcn.h:83
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format fmt)
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:888
octave::stream os
Definition: file-io.cc:627
octave_idx_type length(void) const
Number of elements in the array.
Definition: Array.h:357
virtual std::string string_value(bool force=false) const
Definition: ov-base.cc:791
octave_fcn_inline * fcn_inline_value(bool=false)
Definition: ov-fcn-inline.h:63