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