Mercurial > octave
view libinterp/octave-value/ov-fcn-inline.cc @ 21966:112b20240c87
move docstrings in C++ files out of C strings and into comments
* __contourc__.cc, __dispatch__.cc, __dsearchn__.cc, __ichol__.cc,
__ilu__.cc, __lin_interpn__.cc, __luinc__.cc, __magick_read__.cc,
__pchip_deriv__.cc, __qp__.cc, balance.cc, besselj.cc, betainc.cc,
bitfcns.cc, bsxfun.cc, cellfun.cc, colloc.cc, conv2.cc, daspk.cc,
dasrt.cc, dassl.cc, data.cc, debug.cc, defaults.cc, det.cc, dirfns.cc,
dlmread.cc, dot.cc, eig.cc, ellipj.cc, error.cc, fft.cc, fft2.cc,
fftn.cc, file-io.cc, filter.cc, find.cc, gammainc.cc, gcd.cc,
getgrent.cc, getpwent.cc, getrusage.cc, givens.cc, graphics.cc,
hash.cc, help.cc, hess.cc, hex2num.cc, input.cc, inv.cc, kron.cc,
load-path.cc, load-save.cc, lookup.cc, ls-oct-text.cc, lsode.cc,
lu.cc, mappers.cc, matrix_type.cc, max.cc, mgorth.cc, nproc.cc,
oct-hist.cc, octave-link.cc, ordschur.cc, pager.cc, pinv.cc,
pr-output.cc, profiler.cc, psi.cc, pt-jit.cc, quad.cc, quadcc.cc,
qz.cc, rand.cc, rcond.cc, regexp.cc, schur.cc, sighandlers.cc,
sparse.cc, spparms.cc, sqrtm.cc, str2double.cc, strfind.cc, strfns.cc,
sub2ind.cc, svd.cc, sylvester.cc, symtab.cc, syscalls.cc, sysdep.cc,
time.cc, toplev.cc, tril.cc, tsearch.cc, typecast.cc, urlwrite.cc,
utils.cc, variables.cc, __delaunayn__.cc, __eigs__.cc,
__fltk_uigetfile__.cc, __glpk__.cc, __init_fltk__.cc,
__init_gnuplot__.cc, __osmesa_print__.cc, __voronoi__.cc, amd.cc,
audiodevinfo.cc, audioread.cc, ccolamd.cc, chol.cc, colamd.cc,
convhulln.cc, dmperm.cc, fftw.cc, qr.cc, symbfact.cc, symrcm.cc,
ov-base.cc, ov-bool-mat.cc, ov-cell.cc, ov-class.cc, ov-classdef.cc,
ov-fcn-handle.cc, ov-fcn-inline.cc, ov-flt-re-mat.cc, ov-int16.cc,
ov-int32.cc, ov-int64.cc, ov-int8.cc, ov-java.cc, ov-null-mat.cc,
ov-oncleanup.cc, ov-range.cc, ov-re-mat.cc, ov-struct.cc,
ov-typeinfo.cc, ov-uint16.cc, ov-uint32.cc, ov-uint64.cc, ov-uint8.cc,
ov-usr-fcn.cc, ov.cc, octave.cc, pt-arg-list.cc, pt-binop.cc,
pt-eval.cc, pt-mat.cc, lex.ll, oct-parse.in.yy:
Docstrings are now comments instead of C strings.
* build-aux/mk-opts.pl: Emit docstrings as comments instead of C
strings.
* DASPK-opts.in, LSODE-opts.in: Don't quote " in docstring fragments.
* builtins.h: Include builtin-defun-decls.h unconditionally.
* defun.h (DEFUN, DEFUNX, DEFCONSTFUN): Simply emit declaration.
(DEFALIAS): Always expand to nothing.
* defun-dld.h: No special macro expansions for MAKE_BUILTINS.
(DEFUN_DLD): Use FORWARD_DECLARE_FUN.
(DEFUNX_DLD): Use FORWARD_DECLARE_FUNX.
* defun-int.h: No special macro expansions for MAKE_BUILTINS.
(FORWARD_DECLARE_FUN, FORWARD_DECLARE_FUNX): New macros.
(DEFINE_FUN_INSTALLER_FUN): If compiling an Octave source file, pass
"external-doc" to DEFINE_FUNX_INSTALLER_FUN.
(DEFUN_INTERNAL, DEFCONSTFUN_INTERNAL, DEFUNX_INTERNAL,
DEFALIAS_INTERNAL): Delete.
* common.mk (move_if_change_rule): New macro.
(simple_move_if_change_rule): Define using move_if_change_rule.
* find-defun-files.sh (DEFUN_PATTERN): Update. Don't transform file
name extension to ".df".
* libinterp/mk-pkg-add, gendoc.pl: Operate directly on source files.
* mkbuiltins: New argument, SRCDIR. Operate directly on source files.
* mkdefs: Delete.
* libinterp/module.mk (BUILT_SOURCES): Update list to contain only
files included in other source files.
(GENERATED_MAKE_BUILTINS_INCS, DEF_FILES): Delete.
(LIBINTERP_BUILT_DISTFILES): Include $(OPT_HANDLERS) here.
(LIBINTERP_BUILT_NODISTFILES): Not here. Remove $(ALL_DEF_FILES from
the list.
(libinterp_EXTRA_DIST): Remove mkdefs from the list.
(FOUND_DEFUN_FILES): Rename from SRC_DEF_FILES.
(DLDFCN_DEFUN_FILES): Rename from DLDFCN_DEF_FILES.
(SRC_DEFUN_FILES): Rename from SRC_DEF_FILES.
(ALL_DEFUN_FILES): Rename from ALL_DEF_FILES.
(%.df: %.cc): Delete pattern rule.
(libinterp/build-env-features.cc, libinterp/builtins.cc,
libinterp/dldfcn/PKG_ADD): Use mv instead of move-if-change.
(libinterp/builtins.cc, libinterp/builtin-defun-decls.h):
Update mkbuiltins command.
($(srcdir)/libinterp/DOCSTRINGS): Update gendoc.pl command.
* liboctave/module.mk (BUILT_SOURCES): Don't include
liboctave-build-info.cc in the list.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 21 Jun 2016 16:07:51 -0400 |
parents | c4ab2e54f100 |
children | 0f6fc2ec3b1a |
line wrap: on
line source
/* Copyright (C) 2004-2015 David Bateman This file is part of Octave. Octave is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. Octave is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Octave; see the file COPYING. If not, see <http://www.gnu.org/licenses/>. In addition to the terms of the GPL, you are permitted to link this program with any Open Source program, as defined by the Open Source Initiative (www.opensource.org) */ #if defined (HAVE_CONFIG_H) # include "config.h" #endif #include <istream> #include <iostream> #include <sstream> #include <vector> #include "oct-locbuf.h" #include "defun.h" #include "error.h" #include "errwarn.h" #include "oct-hdf5.h" #include "oct-map.h" #include "ov-base.h" #include "ov-fcn-inline.h" #include "ov-usr-fcn.h" #include "pr-output.h" #include "variables.h" #include "parse.h" #include "toplev.h" #include "byte-swap.h" #include "ls-ascii-helper.h" #include "ls-oct-text.h" #include "ls-hdf5.h" #include "ls-utils.h" DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_fcn_inline, "inline function", "function_handle"); octave_fcn_inline::octave_fcn_inline (const std::string& f, const string_vector& a, const std::string& n) : octave_fcn_handle (n), iftext (f), ifargs (a) { // Form a string representing the function. std::ostringstream buf; buf << "@("; for (int i = 0; i < ifargs.numel (); i++) { if (i > 0) buf << ", "; buf << ifargs(i); } buf << ") " << iftext; int parse_status; octave_value anon_fcn_handle = eval_string (buf.str (), true, parse_status); if (parse_status == 0) { octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value (); if (fh) { fcn = fh->fcn_val (); octave_user_function *uf = fcn.user_function_value (); if (uf) { octave_function *curr_fcn = octave_call_stack::current (); if (curr_fcn) { symbol_table::scope_id parent_scope = curr_fcn->parent_fcn_scope (); if (parent_scope < 0) parent_scope = curr_fcn->scope (); uf->stash_parent_fcn_scope (parent_scope); } } } } if (fcn.is_undefined ()) error ("inline: unable to define function"); } // This function is supplied to allow a Matlab style class structure // to be returned.. octave_map octave_fcn_inline::map_value (void) const { octave_scalar_map m; m.assign ("version", 1.0); m.assign ("isEmpty", 0.0); m.assign ("expr", fcn_text ()); string_vector args = fcn_arg_names (); m.assign ("numArgs", args.numel ()); m.assign ("args", args); std::ostringstream buf; for (int i = 0; i < args.numel (); i++) buf << args(i) << " = INLINE_INPUTS_{" << i + 1 << "}; "; m.assign ("inputExpr", buf.str ()); return m; } bool octave_fcn_inline::save_ascii (std::ostream& os) { os << "# nargs: " << ifargs.numel () << "\n"; for (int i = 0; i < ifargs.numel (); i++) os << ifargs(i) << "\n"; if (nm.length () < 1) // Write an invalid value to flag empty fcn handle name. os << "0\n"; else os << nm << "\n"; os << iftext << "\n"; return true; } bool octave_fcn_inline::load_ascii (std::istream& is) { int nargs; if (extract_keyword (is, "nargs", nargs, true)) { ifargs.resize (nargs); for (int i = 0; i < nargs; i++) is >> ifargs(i); is >> nm; if (nm == "0") nm = ""; skip_preceeding_newline (is); std::string buf; if (is) { // Get a line of text whitespace characters included, // leaving newline in the stream. buf = read_until_newline (is, true); } iftext = buf; octave_fcn_inline tmp (iftext, ifargs, nm); fcn = tmp.fcn; return true; } else return false; } bool octave_fcn_inline::save_binary (std::ostream& os, bool&) { int32_t tmp = ifargs.numel (); os.write (reinterpret_cast<char *> (&tmp), 4); for (int i = 0; i < ifargs.numel (); i++) { tmp = ifargs(i).length (); os.write (reinterpret_cast<char *> (&tmp), 4); os.write (ifargs(i).c_str (), ifargs(i).length ()); } tmp = nm.length (); os.write (reinterpret_cast<char *> (&tmp), 4); os.write (nm.c_str (), nm.length ()); tmp = iftext.length (); os.write (reinterpret_cast<char *> (&tmp), 4); os.write (iftext.c_str (), iftext.length ()); return true; } bool octave_fcn_inline::load_binary (std::istream& is, bool swap, octave::mach_info::float_format) { int32_t nargs; if (! is.read (reinterpret_cast<char *> (&nargs), 4)) return false; if (swap) swap_bytes<4> (&nargs); if (nargs < 1) return false; else { int32_t tmp; ifargs.resize (nargs); for (int i = 0; i < nargs; i++) { if (! is.read (reinterpret_cast<char *> (&tmp), 4)) return false; if (swap) swap_bytes<4> (&tmp); OCTAVE_LOCAL_BUFFER (char, ctmp, tmp+1); is.read (ctmp, tmp); ifargs(i) = std::string (ctmp); if (! is) return false; } if (! is.read (reinterpret_cast<char *> (&tmp), 4)) return false; if (swap) swap_bytes<4> (&tmp); OCTAVE_LOCAL_BUFFER (char, ctmp1, tmp+1); is.read (ctmp1, tmp); nm = std::string (ctmp1); if (! is) return false; if (! is.read (reinterpret_cast<char *> (&tmp), 4)) return false; if (swap) swap_bytes<4> (&tmp); OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1); is.read (ctmp2, tmp); iftext = std::string (ctmp2); if (! is) return false; octave_fcn_inline ftmp (iftext, ifargs, nm); fcn = ftmp.fcn; } return true; } bool octave_fcn_inline::save_hdf5 (octave_hdf5_id loc_id, const char *name, bool /* save_as_floats */) { bool retval = false; #if defined (HAVE_HDF5) hid_t group_hid = -1; #if defined (HAVE_HDF5_18) group_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT, octave_H5P_DEFAULT); #else group_hid = H5Gcreate (loc_id, name, 0); #endif if (group_hid < 0) return false; size_t len = 0; for (int i = 0; i < ifargs.numel (); i++) if (len < ifargs(i).length ()) len = ifargs(i).length (); hid_t space_hid, data_hid, type_hid; space_hid = data_hid = type_hid = -1; // FIXME: Is there a better way of saving string vectors, // than a null padded matrix? OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2); // Octave uses column-major, while HDF5 uses row-major ordering hdims[1] = ifargs.numel (); hdims[0] = len + 1; space_hid = H5Screate_simple (2, hdims, 0); if (space_hid < 0) { H5Gclose (group_hid); return false; } #if defined (HAVE_HDF5_18) data_hid = H5Dcreate (group_hid, "args", H5T_NATIVE_CHAR, space_hid, octave_H5P_DEFAULT, octave_H5P_DEFAULT, octave_H5P_DEFAULT); #else data_hid = H5Dcreate (group_hid, "args", H5T_NATIVE_CHAR, space_hid, octave_H5P_DEFAULT); #endif if (data_hid < 0) { H5Sclose (space_hid); H5Gclose (group_hid); return false; } OCTAVE_LOCAL_BUFFER (char, s, ifargs.numel () * (len + 1)); // Save the args as a null teminated list for (int i = 0; i < ifargs.numel (); i++) { const char * cptr = ifargs(i).c_str (); for (size_t j = 0; j < ifargs(i).length (); j++) s[i*(len+1)+j] = *cptr++; s[ifargs(i).length ()] = '\0'; } retval = H5Dwrite (data_hid, H5T_NATIVE_CHAR, octave_H5S_ALL, octave_H5S_ALL, octave_H5P_DEFAULT, s) >= 0; H5Dclose (data_hid); H5Sclose (space_hid); if (! retval) { H5Gclose (group_hid); return false; } // attach the type of the variable type_hid = H5Tcopy (H5T_C_S1); H5Tset_size (type_hid, nm.length () + 1); if (type_hid < 0) { H5Gclose (group_hid); return false; } hdims[0] = 0; space_hid = H5Screate_simple (0 , hdims, 0); if (space_hid < 0) { H5Tclose (type_hid); H5Gclose (group_hid); return false; } #if defined (HAVE_HDF5_18) data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid, octave_H5P_DEFAULT, octave_H5P_DEFAULT, octave_H5P_DEFAULT); #else data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid, octave_H5P_DEFAULT); #endif if (data_hid < 0 || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL, octave_H5P_DEFAULT, nm.c_str ()) < 0) { H5Sclose (space_hid); H5Tclose (type_hid); H5Gclose (group_hid); return false; } H5Dclose (data_hid); // attach the type of the variable H5Tset_size (type_hid, iftext.length () + 1); if (type_hid < 0) { H5Gclose (group_hid); return false; } #if defined (HAVE_HDF5_18) data_hid = H5Dcreate (group_hid, "iftext", type_hid, space_hid, octave_H5P_DEFAULT, octave_H5P_DEFAULT, octave_H5P_DEFAULT); #else data_hid = H5Dcreate (group_hid, "iftext", type_hid, space_hid, octave_H5P_DEFAULT); #endif if (data_hid < 0 || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL, octave_H5P_DEFAULT, iftext.c_str ()) < 0) { H5Sclose (space_hid); H5Tclose (type_hid); H5Gclose (group_hid); return false; } H5Dclose (data_hid); H5Sclose (space_hid); H5Tclose (type_hid); H5Gclose (group_hid); #else octave_unused_parameter (loc_id); octave_unused_parameter (name); warn_save ("hdf5"); #endif return retval; } bool octave_fcn_inline::load_hdf5 (octave_hdf5_id loc_id, const char *name) { #if defined (HAVE_HDF5) hid_t group_hid, data_hid, space_hid, type_hid, type_class_hid, st_id; hsize_t rank; int slen; #if defined (HAVE_HDF5_18) group_hid = H5Gopen (loc_id, name, octave_H5P_DEFAULT); #else group_hid = H5Gopen (loc_id, name); #endif if (group_hid < 0) return false; #if defined (HAVE_HDF5_18) data_hid = H5Dopen (group_hid, "args", octave_H5P_DEFAULT); #else data_hid = H5Dopen (group_hid, "args"); #endif space_hid = H5Dget_space (data_hid); rank = H5Sget_simple_extent_ndims (space_hid); if (rank != 2) { H5Dclose (data_hid); H5Sclose (space_hid); H5Gclose (group_hid); return false; } OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank); OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank); H5Sget_simple_extent_dims (space_hid, hdims, maxdims); ifargs.resize (hdims[1]); OCTAVE_LOCAL_BUFFER (char, s1, hdims[0] * hdims[1]); if (H5Dread (data_hid, H5T_NATIVE_UCHAR, octave_H5S_ALL, octave_H5S_ALL, octave_H5P_DEFAULT, s1) < 0) { H5Dclose (data_hid); H5Sclose (space_hid); H5Gclose (group_hid); return false; } H5Dclose (data_hid); H5Sclose (space_hid); for (size_t i = 0; i < hdims[1]; i++) ifargs(i) = std::string (s1 + i*hdims[0]); #if defined (HAVE_HDF5_18) data_hid = H5Dopen (group_hid, "nm", octave_H5P_DEFAULT); #else data_hid = H5Dopen (group_hid, "nm"); #endif if (data_hid < 0) { H5Gclose (group_hid); return false; } type_hid = H5Dget_type (data_hid); type_class_hid = H5Tget_class (type_hid); if (type_class_hid != H5T_STRING) { H5Tclose (type_hid); H5Dclose (data_hid); H5Gclose (group_hid); return false; } space_hid = H5Dget_space (data_hid); rank = H5Sget_simple_extent_ndims (space_hid); if (rank != 0) { H5Sclose (space_hid); H5Tclose (type_hid); H5Dclose (data_hid); H5Gclose (group_hid); return false; } slen = H5Tget_size (type_hid); if (slen < 0) { H5Sclose (space_hid); H5Tclose (type_hid); H5Dclose (data_hid); H5Gclose (group_hid); return false; } OCTAVE_LOCAL_BUFFER (char, nm_tmp, slen); // create datatype for (null-terminated) string to read into: st_id = H5Tcopy (H5T_C_S1); H5Tset_size (st_id, slen); if (H5Dread (data_hid, st_id, octave_H5S_ALL, octave_H5S_ALL, octave_H5P_DEFAULT, nm_tmp) < 0) { H5Sclose (space_hid); H5Tclose (type_hid); H5Gclose (group_hid); return false; } H5Tclose (st_id); H5Dclose (data_hid); nm = nm_tmp; #if defined (HAVE_HDF5_18) data_hid = H5Dopen (group_hid, "iftext", octave_H5P_DEFAULT); #else data_hid = H5Dopen (group_hid, "iftext"); #endif if (data_hid < 0) { H5Gclose (group_hid); return false; } type_hid = H5Dget_type (data_hid); type_class_hid = H5Tget_class (type_hid); if (type_class_hid != H5T_STRING) { H5Tclose (type_hid); H5Dclose (data_hid); H5Gclose (group_hid); return false; } space_hid = H5Dget_space (data_hid); rank = H5Sget_simple_extent_ndims (space_hid); if (rank != 0) { H5Sclose (space_hid); H5Tclose (type_hid); H5Dclose (data_hid); H5Gclose (group_hid); return false; } slen = H5Tget_size (type_hid); if (slen < 0) { H5Sclose (space_hid); H5Tclose (type_hid); H5Dclose (data_hid); H5Gclose (group_hid); return false; } OCTAVE_LOCAL_BUFFER (char, iftext_tmp, slen); // create datatype for (null-terminated) string to read into: st_id = H5Tcopy (H5T_C_S1); H5Tset_size (st_id, slen); if (H5Dread (data_hid, st_id, octave_H5S_ALL, octave_H5S_ALL, octave_H5P_DEFAULT, iftext_tmp) < 0) { H5Sclose (space_hid); H5Tclose (type_hid); H5Gclose (group_hid); return false; } H5Tclose (st_id); H5Dclose (data_hid); iftext = iftext_tmp; octave_fcn_inline ftmp (iftext, ifargs, nm); fcn = ftmp.fcn; return true; #else octave_unused_parameter (loc_id); octave_unused_parameter (name); warn_load ("hdf5"); return false; #endif } void octave_fcn_inline::print (std::ostream& os, bool pr_as_read_syntax) { print_raw (os, pr_as_read_syntax); newline (os); } void octave_fcn_inline::print_raw (std::ostream& os, bool pr_as_read_syntax) const { std::ostringstream buf; if (nm.empty ()) buf << "f("; else buf << nm << "("; for (int i = 0; i < ifargs.numel (); i++) { if (i) buf << ", "; buf << ifargs(i); } buf << ") = " << iftext; octave_print_internal (os, buf.str (), pr_as_read_syntax, current_print_indent_level ()); } octave_value octave_fcn_inline::convert_to_str_internal (bool, bool, char type) const { return octave_value (fcn_text (), type); } DEFUNX ("inline", Finline, args, , doc: /* -*- texinfo -*- @deftypefn {} {} inline (@var{str}) @deftypefnx {} {} inline (@var{str}, @var{arg1}, @dots{}) @deftypefnx {} {} inline (@var{str}, @var{n}) Create an inline function from the character string @var{str}. If called with a single argument, 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 constant. All arguments followed by a parenthesis are considered to be functions. If no arguments are found, a function taking a single argument named @code{x} will be created. If the second and subsequent arguments are character strings, they are the names of the arguments of the function. If the second argument is an integer @var{n}, the arguments are @qcode{"x"}, @qcode{"P1"}, @dots{}, @qcode{"P@var{N}"}. Programming Note: The use of @code{inline} is discouraged and it may be removed from a future version of Octave. The preferred way to create functions from strings is through the use of anonymous functions (@pxref{Anonymous Functions}) or @code{str2func}. @seealso{argnames, formula, vectorize, str2func} @end deftypefn */) { int nargin = args.length (); if (nargin == 0) print_usage (); std::string fun = args(0).xstring_value ("inline: STR argument must be a string"); string_vector fargs; if (nargin == 1) { bool is_arg = false; bool in_string = false; std::string tmp_arg; size_t i = 0; size_t fun_length = fun.length (); while (i < fun_length) { bool terminate_arg = false; char c = fun[i++]; if (in_string) { if (c == '\'' || c == '\"') in_string = false; } else if (c == '\'' || c == '\"') { in_string = true; if (is_arg) terminate_arg = true; } else if (! isalpha (c) && c != '_') if (! is_arg) continue; else if (isdigit (c)) tmp_arg.append (1, c); else { // Before we do anything remove trailing whitespaces. while (i < fun_length && isspace (c)) c = fun[i++]; // Do we have a variable or a function? if (c != '(') terminate_arg = true; else { tmp_arg = ""; is_arg = false; } } else if (! is_arg) { if (c == 'e' || c == 'E') { // possible number in exponent form, not arg if (isdigit (fun[i]) || fun[i] == '-' || fun[i] == '+') continue; } is_arg = true; tmp_arg.append (1, c); } else { tmp_arg.append (1, c); } if (terminate_arg || (i == fun_length && is_arg)) { bool have_arg = false; for (int j = 0; j < fargs.numel (); j++) if (tmp_arg == fargs (j)) { have_arg = true; break; } if (! have_arg && tmp_arg != "i" && tmp_arg != "j" && tmp_arg != "NaN" && tmp_arg != "nan" && tmp_arg != "Inf" && tmp_arg != "inf" && tmp_arg != "NA" && tmp_arg != "pi" && tmp_arg != "e" && tmp_arg != "eps") fargs.append (tmp_arg); tmp_arg = ""; is_arg = false; } } // Sort the arguments into ascii order. fargs.sort (); if (fargs.is_empty ()) fargs.append (std::string ("x")); } else if (nargin == 2 && args(1).is_numeric_type ()) { if (! args(1).is_scalar_type ()) error ("inline: N must be an integer"); int n = args(1).int_value ("inline: N must be an integer"); if (n < 0) error ("inline: N must be a positive integer or zero"); fargs.resize (n+1); fargs(0) = "x"; for (int i = 1; i < n+1; i++) { std::ostringstream buf; buf << "P" << i; fargs(i) = buf.str (); } } else { fargs.resize (nargin - 1); for (int i = 1; i < nargin; i++) { std::string s = args(i).xstring_value ("inline: additional arguments must be strings"); fargs(i-1) = s; } } return ovl (new octave_fcn_inline (fun, fargs)); } /* %!shared fn %! fn = inline ("x.^2 + 1"); %!assert (feval (fn, 6), 37) %!assert (fn (6), 37) %!assert (feval (inline ("sum (x(:))"), [1 2; 3 4]), 10) %!assert (feval (inline ("sqrt (x^2 + y^2)", "x", "y"), 3, 4), 5) %!assert (feval (inline ("exp (P1*x) + P2", 3), 3, 4, 5), exp(3*4) + 5) ## Test input validation %!error inline () %!error <STR argument must be a string> inline (1) %!error <N must be an integer> inline ("2", ones (2,2)) %!error <N must be a positive integer> inline ("2", -1) %!error <additional arguments must be strings> inline ("2", "x", -1, "y") */ DEFUN (formula, args, , doc: /* -*- texinfo -*- @deftypefn {} {} formula (@var{fun}) Return a character string representing the inline function @var{fun}. Note that @code{char (@var{fun})} is equivalent to @code{formula (@var{fun})}. @seealso{char, argnames, inline, vectorize} @end deftypefn */) { if (args.length () != 1) print_usage (); octave_fcn_inline* fn = args(0).fcn_inline_value (true); if (! fn) error ("formula: FUN must be an inline function"); return ovl (fn->fcn_text ()); } /* %!assert (formula (fn), "x.^2 + 1") %!assert (formula (fn), char (fn)) ## Test input validation %!error formula () %!error formula (1, 2) %!error <FUN must be an inline function> formula (1) */ DEFUN (argnames, args, , doc: /* -*- texinfo -*- @deftypefn {} {} argnames (@var{fun}) Return a cell array of character strings containing the names of the arguments of the inline function @var{fun}. @seealso{inline, formula, vectorize} @end deftypefn */) { if (args.length () != 1) print_usage (); octave_fcn_inline *fn = args(0).fcn_inline_value (true); if (! fn) error ("argnames: FUN must be an inline function"); string_vector t1 = fn->fcn_arg_names (); Cell t2 (dim_vector (t1.numel (), 1)); for (int i = 0; i < t1.numel (); i++) t2(i) = t1(i); return ovl (t2); } /* %!assert (argnames (fn), {"x"}) %!assert (argnames (inline ("1e-3*y + 2e4*z")), {"y"; "z"}) %!assert (argnames (inline ("2", 2)), {"x"; "P1"; "P2"}) ## Test input validation %!error argnames () %!error argnames (1, 2) %!error <FUN must be an inline function> argnames (1) */ DEFUN (vectorize, args, , doc: /* -*- texinfo -*- @deftypefn {} {} vectorize (@var{fun}) Create a vectorized version of the inline function @var{fun} by replacing all occurrences of @code{*}, @code{/}, etc., with @code{.*}, @code{./}, etc. This may be useful, for example, when using inline functions with numerical integration or optimization where a vector-valued function is expected. @example @group fcn = vectorize (inline ("x^2 - 1")) @result{} fcn = f(x) = x.^2 - 1 quadv (fcn, 0, 3) @result{} 6 @end group @end example @seealso{inline, formula, argnames} @end deftypefn */) { if (args.length () != 1) print_usage (); std::string old_func; octave_fcn_inline* old = 0; bool func_is_string = true; if (args(0).is_string ()) old_func = args(0).string_value (); else { old = args(0).fcn_inline_value (true); func_is_string = false; if (old) old_func = old->fcn_text (); else error ("vectorize: FUN must be a string or inline function"); } std::string new_func; size_t i = 0; while (i < old_func.length ()) { std::string t1 = old_func.substr (i, 1); if (t1 == "*" || t1 == "/" || t1 == "\\" || t1 == "^") { if (i && old_func.substr (i-1, 1) != ".") new_func.append ("."); // Special case for ** operator. if (t1 == "*" && i < (old_func.length () - 1) && old_func.substr (i+1, 1) == "*") { new_func.append ("*"); i++; } } new_func.append (t1); i++; } if (func_is_string) return ovl (new_func); else return ovl (new octave_fcn_inline (new_func, old->fcn_arg_names ())); } /* %!assert (char (vectorize (fn)), "x.^2 + 1") %!assert (char (vectorize (inline ("1e-3*y + 2e4*z"))), "1e-3.*y + 2e4.*z") %!assert (char (vectorize (inline ("2**x^5"))), "2.**x.^5") %!assert (vectorize ("x.^2 + 1"), "x.^2 + 1") %!assert (vectorize ("1e-3*y + 2e4*z"), "1e-3.*y + 2e4.*z") %!assert (vectorize ("2**x^5"), "2.**x.^5") ## Test input validation %!error vectorize () %!error vectorize (1, 2) %!error <FUN must be a string or inline function> vectorize (1) */