# HG changeset patch # User John W. Eaton # Date 1669993960 18000 # Node ID 3b7852a822e8d15a6edfaaac2a8bda43f0c266a9 # Parent 23664317f0d3cd4e7dc462d00e8e430e228f9add# Parent c2a0e546aab1e882797cba5d994125c2eaf38c5e maint: Merge stable to default. diff -r c2a0e546aab1 -r 3b7852a822e8 .github/workflows/make.yaml --- a/.github/workflows/make.yaml Fri Dec 02 10:11:46 2022 -0500 +++ b/.github/workflows/make.yaml Fri Dec 02 10:12:40 2022 -0500 @@ -85,7 +85,7 @@ key: ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ github.ref }}:${{ steps.ccache_cache_timestamp.outputs.timestamp }}:${{ github.sha }} restore-keys: | ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ github.ref }} - ccache:${{ matrix.os }}:${{ matrix.compiler }}:refs/heads/stable + ccache:${{ matrix.os }}:${{ matrix.compiler }}:refs/heads/default - name: configure ccache env: @@ -239,7 +239,7 @@ key: ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ github.ref }}:${{ steps.ccache_cache_timestamp.outputs.timestamp }}:${{ github.sha }} restore-keys: | ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ github.ref }} - ccache:${{ matrix.os }}:${{ matrix.compiler }}:refs/heads/stable + ccache:${{ matrix.os }}:${{ matrix.compiler }}:refs/heads/default - name: configure ccache # The cache doesn't seem to compress well on macOS. Is it already compressed? @@ -468,7 +468,7 @@ key: ccache:${{ matrix.os }}:${{ matrix.msystem }}:${{ github.ref }}:${{ steps.ccache_cache_timestamp.outputs.timestamp }}:${{ github.sha }} restore-keys: | ccache:${{ matrix.os }}:${{ matrix.msystem }}:${{ github.ref }} - ccache:${{ matrix.os }}:${{ matrix.msystem }}:refs/heads/stable + ccache:${{ matrix.os }}:${{ matrix.msystem }}:refs/heads/default - name: configure ccache # Limit the maximum size and switch on compression to avoid exceeding the total disk or cache quota. @@ -707,7 +707,7 @@ key: ccache:${{ matrix.os }}:cygwin:${{ github.ref }}:${{ steps.ccache_cache_timestamp.outputs.timestamp }}:${{ github.sha }} restore-keys: | ccache:${{ matrix.os }}:cygwin:${{ github.ref }} - ccache:${{ matrix.os }}:cygwin:refs/heads/stable + ccache:${{ matrix.os }}:cygwin:refs/heads/default - name: configure ccache run: | diff -r c2a0e546aab1 -r 3b7852a822e8 configure.ac --- a/configure.ac Fri Dec 02 10:11:46 2022 -0500 +++ b/configure.ac Fri Dec 02 10:12:40 2022 -0500 @@ -27,7 +27,7 @@ ### Initialize Autoconf AC_PREREQ([2.65]) -AC_INIT([GNU Octave], [8.0.1], [https://octave.org/bugs.html], [octave], +AC_INIT([GNU Octave], [9.0.0], [https://octave.org/bugs.html], [octave], [https://www.gnu.org/software/octave/]) ### Declare version numbers @@ -39,9 +39,9 @@ ## explains how to update these numbers for release and development ## versions. -OCTAVE_MAJOR_VERSION=8 +OCTAVE_MAJOR_VERSION=9 OCTAVE_MINOR_VERSION=0 -OCTAVE_PATCH_VERSION=1 +OCTAVE_PATCH_VERSION=0 dnl PACKAGE_VERSION is set by the AC_INIT VERSION argument. OCTAVE_VERSION="$PACKAGE_VERSION" diff -r c2a0e546aab1 -r 3b7852a822e8 doc/interpreter/contributors.in --- a/doc/interpreter/contributors.in Fri Dec 02 10:11:46 2022 -0500 +++ b/doc/interpreter/contributors.in Fri Dec 02 10:12:40 2022 -0500 @@ -101,6 +101,7 @@ Massimiliano Fasi Stephen Fegan Ramon Garcia Fernandez +Kasper H. Filtenborg Torsten Finke David Finkel Guillaume Flandin diff -r c2a0e546aab1 -r 3b7852a822e8 doc/interpreter/linalg.txi --- a/doc/interpreter/linalg.txi Fri Dec 02 10:11:46 2022 -0500 +++ b/doc/interpreter/linalg.txi Fri Dec 02 10:12:40 2022 -0500 @@ -211,6 +211,8 @@ @DOCSTRING(kron) +@DOCSTRING(tensorprod) + @DOCSTRING(blkmm) @DOCSTRING(sylvester) diff -r c2a0e546aab1 -r 3b7852a822e8 doc/liboctave/range.texi --- a/doc/liboctave/range.texi Fri Dec 02 10:11:46 2022 -0500 +++ b/doc/liboctave/range.texi Fri Dec 02 10:12:40 2022 -0500 @@ -20,35 +20,4 @@ @chapter Ranges @cindex ranges -@deftypefn {} {} Range (void) -@deftypefnx {} {} Range (const Range &@var{r}) -@deftypefnx {} {} Range (double @var{b}, double @var{l}) -@deftypefnx {} {} Range (double @var{b}, double @var{l}, double @var{i}) -@end deftypefn - -@deftypefn {} double base (void) const -@deftypefnx {} double limit (void) const -@deftypefnx {} double inc (void) const -@end deftypefn - -@deftypefn {} void set_base (double @var{b}) -@deftypefnx {} void set_limit (double @var{l}) -@deftypefnx {} void set_inc (double @var{i}) -@end deftypefn - -@deftypefn {} int nelem (void) const -@end deftypefn - -@deftypefn {} double min (void) const -@deftypefnx {} double max (void) const -@end deftypefn - -@deftypefn {} void sort (void) -@end deftypefn - -@deftypefn {} {ostream&} {operator <<} (ostream &@var{os}, const Range &@var{r}) -@deftypefnx {} {istream&} {operator >>} (istream &@var{is}, Range &@var{r}) -@end deftypefn - -@deftypefn {} void print_range (void) -@end deftypefn +FIXME: The @code{Range} class is obsolete. diff -r c2a0e546aab1 -r 3b7852a822e8 etc/NEWS.8.md diff -r c2a0e546aab1 -r 3b7852a822e8 etc/NEWS.9.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/etc/NEWS.9.md Fri Dec 02 10:12:40 2022 -0500 @@ -0,0 +1,93 @@ +Summary of important user-visible changes for version 9 (yyyy-mm-dd): +--------------------------------------------------------------------- + +### General improvements + +- `oruntests`: The current directory now changes to the directory +containing the files with the tests for the duration of the test. This +aligns the behavior of this function with Octave's test suite. This also +means that the file encoding specified in the `.oct-config` file for the +respective directory is taken into account for the tests. + +### Graphical User Interface + +### Graphics backend + +### Matlab compatibility + +### Alphabetical list of new functions added in Octave 9 + +* `tensorprod` + +### Deprecated functions, properties, and operators + +The following functions and properties have been deprecated in Octave 9 +and will be removed from Octave 11 (or whatever version is the second +major release after 9): + +- Functions + + Function | Replacement + -----------------------|------------------ + +- Properties + + The following property names are discouraged, but there is no fixed + date for their removal. + + Object | Property | Replacement + -----------------|-------------|------------ + +The following features were deprecated in Octave 7 and have been removed +from Octave 9. + +- Functions + + Function | Replacement + ---------------------------|------------------ + disable_diagonal_matrix | optimize_diagonal_matrix + disable_permutation_matrix | optimize_permutation_matrix + disable_range | optimize_range + +- Operators + + Operator | Replacement + ---------|------------ + .+ | + + .+= | += + .- | - + .-= | -= + ** | ^ + **= | ^= + .** | .^ + .**= | .^= + +- Interpreter + + * The use of `'...'` for line continuations *inside* double-quoted + strings has been removed. Use `'\'` for line continuations inside strings + instead. + + * The use of `'\'` as a line continuation *outside* of double-quoted + strings has been removed. Use `'...'` for line continuations instead. + + * Support for trailing whitespace after a `'\'` line continuation has been + removed. Delete unnecessary trailing whitespace. + +- For plot functions, the use of numbers to select line colors in + shorthand formats was an undocumented feature was removed from Octave 9. + +- The environment variable used by `mkoctfile` for linker flags is now + `LDFLAGS` rather than `LFLAGS`. `LFLAGS` was deprecated in Octave 6 + and has been removed. + +### Old release news + +- [Octave 8.x](etc/NEWS.8) +- [Octave 7.x](etc/NEWS.7) +- [Octave 6.x](etc/NEWS.6) +- [Octave 5.x](etc/NEWS.5) +- [Octave 4.x](etc/NEWS.4) +- [Octave 3.x](etc/NEWS.3) +- [Octave 2.x](etc/NEWS.2) +- [Octave 1.x](etc/NEWS.1) diff -r c2a0e546aab1 -r 3b7852a822e8 etc/module.mk --- a/etc/module.mk Fri Dec 02 10:11:46 2022 -0500 +++ b/etc/module.mk Fri Dec 02 10:12:40 2022 -0500 @@ -13,6 +13,7 @@ %reldir%/NEWS.6.md \ %reldir%/NEWS.7.md \ %reldir%/NEWS.8.md \ + %reldir%/NEWS.9.md \ %reldir%/gdbinit %canon_reldir%_EXTRA_DIST += \ diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/c-file-ptr-stream.h --- a/libinterp/corefcn/c-file-ptr-stream.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/c-file-ptr-stream.h Fri Dec 02 10:12:40 2022 -0500 @@ -232,39 +232,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::i_c_file_ptr_stream' instead") -typedef octave::i_c_file_ptr_stream i_c_file_ptr_stream; - -OCTAVE_DEPRECATED (7, "use 'octave::o_c_file_ptr_stream' instead") -typedef octave::o_c_file_ptr_stream o_c_file_ptr_stream; - -OCTAVE_DEPRECATED (7, "use 'octave::io_c_file_ptr_stream' instead") -typedef octave::io_c_file_ptr_stream io_c_file_ptr_stream; - -// FIXME: HAVE_ZLIB is not defined here because we do not (and should -// not) include config.h in this header file. We need to find a way to -// define this interface without exposing gzFile. Should this be a -// private header that can only be used if included after config.h in an -// Octave source file and not inside another header file? - -# if defined (HAVE_ZLIB) - -OCTAVE_DEPRECATED (7, "use 'octave::i_c_zfile_ptr_stream' instead") -typedef octave::c_file_ptr_stream - i_c_zfile_ptr_stream; - -OCTAVE_DEPRECATED (7, "use 'octave::o_c_zfile_ptr_stream' instead") -typedef octave::c_file_ptr_stream - o_c_zfile_ptr_stream; - -OCTAVE_DEPRECATED (7, "use 'octave::io_c_zfile_ptr_stream' instead") -typedef octave::c_file_ptr_stream - io_c_zfile_ptr_stream; - -# endif - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/data.cc --- a/libinterp/corefcn/data.cc Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/data.cc Fri Dec 02 10:12:40 2022 -0500 @@ -6523,7 +6523,7 @@ (@dots{}((@var{A1} * @var{A2}) * @var{A3}) * @dots{}) @end example -@seealso{times, plus, minus, rdivide, mrdivide, mldivide, mpower} +@seealso{times, plus, minus, rdivide, mrdivide, mldivide, mpower, tensorprod} @end deftypefn */) { return binary_assoc_op_defun_body (octave_value::op_mul, diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/data.h --- a/libinterp/corefcn/data.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/data.h Fri Dec 02 10:12:40 2022 -0500 @@ -41,14 +41,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) -OCTAVE_DEPRECATED (7, "use 'octave::do_class_concat' instead") -inline OCTINTERP_API octave_value -do_class_concat (const octave_value_list& ovl, const std::string& cattype, - int dim) -{ - return octave::do_class_concat (ovl, cattype, dim); -} #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/dot.cc --- a/libinterp/corefcn/dot.cc Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/dot.cc Fri Dec 02 10:12:40 2022 -0500 @@ -91,7 +91,7 @@ the result is equivalent to @code{@var{X}' * @var{Y}}. Although, @code{dot} is defined for integer arrays, the output may differ from the expected result due to the limited range of integer objects. -@seealso{cross, divergence} +@seealso{cross, divergence, tensorprod} @end deftypefn */) { int nargin = args.length (); diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/error.cc --- a/libinterp/corefcn/error.cc Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/error.cc Fri Dec 02 10:12:40 2022 -0500 @@ -901,17 +901,6 @@ last_error_stack (make_stack_map (ee.stack_info ())); } -// DEPRECATED in Octave 7. -void error_system::display_exception (const execution_exception& ee, - std::ostream& os) const -{ - if (m_beep_on_error) - os << "\a"; - - ee.display (octave_diary); - ee.display (os); -} - void error_system::display_exception (const execution_exception& ee) const { // FIXME: How should we handle beep_on_error? diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/error.h --- a/libinterp/corefcn/error.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/error.h Fri Dec 02 10:12:40 2022 -0500 @@ -334,13 +334,6 @@ OCTINTERP_API void save_exception (const execution_exception& ee); - // FIXME - //#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - OCTAVE_DEPRECATED (7, "second argument is no longer accepted") - OCTINTERP_API void display_exception (const execution_exception& ee, - std::ostream& os) const; - //#endif - OCTINTERP_API void display_exception (const execution_exception& ee) const; private: @@ -573,44 +566,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) -OCTAVE_DEPRECATED (7, "use 'octave::defun_usage_message' instead") -inline void defun_usage_message (const std::string& msg) -{ - octave::defun_usage_message (msg); -} - -OCTAVE_DEPRECATED (7, "use 'octave::set_warning_state' instead") -inline octave_value_list -set_warning_state (const std::string& id, const std::string& state) -{ - return octave::set_warning_state (id, state); -} - -OCTAVE_DEPRECATED (7, "use 'octave::set_warning_state' instead") -inline octave_value_list set_warning_state (const octave_value_list& args) -{ - return octave::set_warning_state (args); -} - -OCTAVE_DEPRECATED (7, "use 'octave::warning_enabled' instead") -inline int warning_enabled (const std::string& id) -{ - return octave::warning_enabled (id); -} - -OCTAVE_DEPRECATED (7, "use 'octave::disable_warning' instead") -inline void disable_warning (const std::string& id) -{ - octave::disable_warning (id); -} - -OCTAVE_DEPRECATED (7, "use 'octave::interpreter_try' instead") -inline void interpreter_try (octave::unwind_protect& uwp) -{ - octave::interpreter_try (uwp); -} - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/graphics.in.h --- a/libinterp/corefcn/graphics.in.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/graphics.in.h Fri Dec 02 10:12:40 2022 -0500 @@ -6958,164 +6958,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::base_scaler' instead") -typedef octave::base_scaler base_scaler; - -OCTAVE_DEPRECATED (7, "use 'octave::lin_scaler' instead") -typedef octave::lin_scaler lin_scaler; - -OCTAVE_DEPRECATED (7, "use 'octave::log_scaler' instead") -typedef octave::log_scaler log_scaler; - -OCTAVE_DEPRECATED (7, "use 'octave::neg_log_scaler' instead") -typedef octave::neg_log_scaler neg_log_scaler; - -OCTAVE_DEPRECATED (7, "use 'octave::scaler' instead") -typedef octave::scaler scaler; - -OCTAVE_DEPRECATED (7, "use 'octave::base_property' instead") -typedef octave::base_property base_property; - -OCTAVE_DEPRECATED (7, "use 'octave::string_property' instead") -typedef octave::string_property string_property; - -OCTAVE_DEPRECATED (7, "use 'octave::string_array_property' instead") -typedef octave::string_array_property string_array_property; - -OCTAVE_DEPRECATED (7, "use 'octave::text_label_property' instead") -typedef octave::text_label_property text_label_property; - -OCTAVE_DEPRECATED (7, "use 'octave::radio_values' instead") -typedef octave::radio_values radio_values; - -OCTAVE_DEPRECATED (7, "use 'octave::radio_property' instead") -typedef octave::radio_property radio_property; - -OCTAVE_DEPRECATED (7, "use 'octave::color_values' instead") -typedef octave::color_values color_values; - -OCTAVE_DEPRECATED (7, "use 'octave::color_property' instead") -typedef octave::color_property color_property; - -OCTAVE_DEPRECATED (7, "use 'octave::double_property' instead") -typedef octave::double_property double_property; - -OCTAVE_DEPRECATED (7, "use 'octave::double_radio_property' instead") -typedef octave::double_radio_property double_radio_property; - -OCTAVE_DEPRECATED (7, "use 'octave::array_property' instead") -typedef octave::array_property array_property; - -OCTAVE_DEPRECATED (7, "use 'octave::row_vector_property' instead") -typedef octave::row_vector_property row_vector_property; - -OCTAVE_DEPRECATED (7, "use 'octave::bool_property' instead") -typedef octave::bool_property bool_property; - -OCTAVE_DEPRECATED (7, "use 'octave::handle_property' instead") -typedef octave::handle_property handle_property; - -OCTAVE_DEPRECATED (7, "use 'octave::any_property' instead") -typedef octave::any_property any_property; - -OCTAVE_DEPRECATED (7, "use 'octave::children_property' instead") -typedef octave::children_property children_property; - -OCTAVE_DEPRECATED (7, "use 'octave::callback_property' instead") -typedef octave::callback_property callback_property; - -OCTAVE_DEPRECATED (7, "use 'octave::property' instead") -typedef octave::property property; - -OCTAVE_DEPRECATED (7, "use 'octave::pval_vector' instead") -typedef octave::pval_vector pval_vector; - -OCTAVE_DEPRECATED (7, "use 'octave::property_list' instead") -typedef octave::property_list property_list; - -OCTAVE_DEPRECATED (7, "use 'octave::base_properties' instead") -typedef octave::base_properties base_properties; - -OCTAVE_DEPRECATED (7, "use 'octave::base_graphics_object' instead") -typedef octave::base_graphics_object base_graphics_object; - -OCTAVE_DEPRECATED (7, "use 'octave::graphics_object' instead") -typedef octave::graphics_object graphics_object; - -OCTAVE_DEPRECATED (7, "use 'octave::root_figure' instead") -typedef octave::root_figure root_figure; - -OCTAVE_DEPRECATED (7, "use 'octave::figure' instead") -typedef octave::figure figure; - -OCTAVE_DEPRECATED (7, "use 'octave::graphics_xform' instead") -typedef octave::graphics_xform graphics_xform; - -OCTAVE_DEPRECATED (7, "use 'octave::axes' instead") -typedef octave::axes axes; - -OCTAVE_DEPRECATED (7, "use 'octave::line' instead") -typedef octave::line line; - -OCTAVE_DEPRECATED (7, "use 'octave::text' instead") -typedef octave::text text; - -OCTAVE_DEPRECATED (7, "use 'octave::image' instead") -typedef octave::image image; - -OCTAVE_DEPRECATED (7, "use 'octave::light' instead") -typedef octave::light light; - -OCTAVE_DEPRECATED (7, "use 'octave::patch' instead") -typedef octave::patch patch; - -OCTAVE_DEPRECATED (7, "use 'octave::scatter' instead") -typedef octave::scatter scatter; - -OCTAVE_DEPRECATED (7, "use 'octave::surface' instead") -typedef octave::surface surface; - -OCTAVE_DEPRECATED (7, "use 'octave::hggroup' instead") -typedef octave::hggroup hggroup; - -OCTAVE_DEPRECATED (7, "use 'octave::uimenu' instead") -typedef octave::uimenu uimenu; - -OCTAVE_DEPRECATED (7, "use 'octave::uicontextmenu' instead") -typedef octave::uicontextmenu uicontextmenu; - -OCTAVE_DEPRECATED (7, "use 'octave::uicontrol' instead") -typedef octave::uicontrol uicontrol; - -OCTAVE_DEPRECATED (7, "use 'octave::uibuttongroup' instead") -typedef octave::uibuttongroup uibuttongroup; - -OCTAVE_DEPRECATED (7, "use 'octave::uipanel' instead") -typedef octave::uipanel uipanel; - -OCTAVE_DEPRECATED (7, "use 'octave::uitable' instead") -typedef octave::uitable uitable; - -OCTAVE_DEPRECATED (7, "use 'octave::uitoolbar' instead") -typedef octave::uitoolbar uitoolbar; - -OCTAVE_DEPRECATED (7, "use 'octave::uipushtool' instead") -typedef octave::uipushtool uipushtool; - -OCTAVE_DEPRECATED (7, "use 'octave::uitoggletool' instead") -typedef octave::uitoggletool uitoggletool; - -OCTAVE_DEPRECATED (7, "use 'octave::base_graphics_event' instead") -typedef octave::base_graphics_event base_graphics_event; - -OCTAVE_DEPRECATED (7, "use 'octave::graphics_event' instead") -typedef octave::graphics_event graphics_event; - -OCTAVE_DEPRECATED (7, "use 'octave::gh_manager' instead") -typedef octave::gh_manager gh_manager; - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/hook-fcn.h --- a/libinterp/corefcn/hook-fcn.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/hook-fcn.h Fri Dec 02 10:12:40 2022 -0500 @@ -214,21 +214,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) -OCTAVE_DEPRECATED (7, "use 'octave::base_hook_function' instead") -typedef octave::base_hook_function base_hook_function; - -OCTAVE_DEPRECATED (7, "use 'octave::hook_function' instead") -typedef octave::hook_function hook_function; - -OCTAVE_DEPRECATED (7, "use 'octave::named_hook_function' instead") -typedef octave::named_hook_function named_hook_function; - -OCTAVE_DEPRECATED (7, "use 'octave::fcn_handle_hook_function' instead") -typedef octave::fcn_handle_hook_function fcn_handle_hook_function; - -OCTAVE_DEPRECATED (7, "use 'octave::hook_function_list' instead") -typedef octave::hook_function_list hook_function_list; #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/kron.cc --- a/libinterp/corefcn/kron.cc Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/kron.cc Fri Dec 02 10:12:40 2022 -0500 @@ -275,6 +275,7 @@ @noindent Since the Kronecker product is associative, this is well-defined. +@seealso{tensorprod} @end deftypefn */) { int nargin = args.length (); diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/load-save.cc --- a/libinterp/corefcn/load-save.cc Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/load-save.cc Fri Dec 02 10:12:40 2022 -0500 @@ -2060,13 +2060,3 @@ } OCTAVE_END_NAMESPACE(octave) - -// DEPRECATED in Octave 7 - -void -dump_octave_core (void) -{ - octave::load_save_system& load_save_sys = octave::__get_load_save_system__ (); - - load_save_sys.dump_octave_core (); -} diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/load-save.h --- a/libinterp/corefcn/load-save.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/load-save.h Fri Dec 02 10:12:40 2022 -0500 @@ -294,7 +294,4 @@ OCTAVE_END_NAMESPACE(octave) -OCTAVE_DEPRECATED (7, "use 'load_save_system::dump_octave_core' instead") -extern OCTINTERP_API void dump_octave_core (void); - #endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/ls-ascii-helper.h --- a/libinterp/corefcn/ls-ascii-helper.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/ls-ascii-helper.h Fri Dec 02 10:12:40 2022 -0500 @@ -44,29 +44,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::skip_until_newline' instead") -inline void -skip_until_newline (std::istream& is, bool keep_newline = false) -{ - return octave::skip_until_newline (is, keep_newline); -} - -OCTAVE_DEPRECATED (7, "use 'octave::skip_preceding_newline' instead") -inline void -skip_preceeding_newline (std::istream& is) -{ - return octave::skip_preceeding_newline (is); -} - -OCTAVE_DEPRECATED (7, "use 'octave::read_until_newline' instead") -inline std::string -read_until_newline (std::istream& is, bool keep_newline = false) -{ - return octave::read_until_newline (is, keep_newline); -} - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/ls-utils.h --- a/libinterp/corefcn/ls-utils.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/ls-utils.h Fri Dec 02 10:12:40 2022 -0500 @@ -40,22 +40,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::get_save_type' instead") -inline save_type -get_save_type (double max_val, double min_val) -{ - return octave::get_save_type (max_val, min_val); -} - -OCTAVE_DEPRECATED (7, "use 'octave::get_save_type' instead") -inline save_type -get_save_type (float max_val, float min_val) -{ - return octave::get_save_type (max_val, min_val); -} - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/oct-fstrm.h --- a/libinterp/corefcn/oct-fstrm.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/oct-fstrm.h Fri Dec 02 10:12:40 2022 -0500 @@ -90,11 +90,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::fstream' instead") -typedef octave::fstream octave_fstream; - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/oct-hdf5-types.h --- a/libinterp/corefcn/oct-hdf5-types.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/oct-hdf5-types.h Fri Dec 02 10:12:40 2022 -0500 @@ -38,16 +38,6 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::check_hdf5_types' instead") -inline bool check_hdf5_types (bool warn = true) -{ - return octave::check_hdf5_types (warn); -} - -#endif - #endif // Available for C and C++. diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/oct-iostrm.h --- a/libinterp/corefcn/oct-iostrm.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/oct-iostrm.h Fri Dec 02 10:12:40 2022 -0500 @@ -161,17 +161,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::base_iostream' instead") -typedef octave::base_iostream octave_base_iostream; - -OCTAVE_DEPRECATED (7, "use 'octave::istream' instead") -typedef octave::istream octave_istream; - -OCTAVE_DEPRECATED (7, "use 'octave::ostream' instead") -typedef octave::ostream octave_ostream; - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/oct-prcstrm.h --- a/libinterp/corefcn/oct-prcstrm.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/oct-prcstrm.h Fri Dec 02 10:12:40 2022 -0500 @@ -98,14 +98,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::octave_iprocstream' instead") -typedef octave::octave_iprocstream octave_iprocstream; - -OCTAVE_DEPRECATED (7, "use 'octave::octave_oprocstream' instead") -typedef octave::octave_oprocstream octave_oprocstream; - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/oct-procbuf.h --- a/libinterp/corefcn/oct-procbuf.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/oct-procbuf.h Fri Dec 02 10:12:40 2022 -0500 @@ -83,11 +83,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use octave::procbuf' instead") -typedef octave::procbuf procbuf; - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/oct-stdstrm.h --- a/libinterp/corefcn/oct-stdstrm.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/oct-stdstrm.h Fri Dec 02 10:12:40 2022 -0500 @@ -199,14 +199,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::stdiostream' instead") -typedef octave::stdiostream octave_stdiostream; - -OCTAVE_DEPRECATED (7, "use 'octave::zstdiostream' instead") -typedef octave::zstdiostream octave_zstdiostream; - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/oct-stream.cc --- a/libinterp/corefcn/oct-stream.cc Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/oct-stream.cc Fri Dec 02 10:12:40 2022 -0500 @@ -4288,6 +4288,9 @@ { T value = T (); + is >> std::ws; // skip through whitespace and advance stream pointer + std::streampos pos = is.tellg (); + switch (fmt.type) { case 'o': @@ -4301,11 +4304,7 @@ case 'i': { - int c1 = std::istream::traits_type::eof (); - - while (is && (c1 = is.get ()) != std::istream::traits_type::eof () - && isspace (c1)) - ; // skip whitespace + int c1 = is.get (); if (c1 != std::istream::traits_type::eof ()) { @@ -4354,18 +4353,33 @@ break; } - // If conversion produces an integer that overflows, failbit is set but - // value is non-zero. We want to treat this case as success, so clear - // failbit from the stream state to keep going. - // FIXME: Maybe set error state on octave stream as above? Matlab does - // *not* indicate an error message on overflow. - if ((is.rdstate () & std::ios::failbit) && value != T ()) - is.clear (is.rdstate () & ~std::ios::failbit); - - // Only copy the converted value if the stream is in a state where we - // want to continue reading. - if (! (is.rdstate () & std::ios::failbit)) - *valptr = value; + std::ios::iostate status = is.rdstate (); + if (! (status & std::ios::failbit)) + { + // Copy the converted value if the stream is in a good state + *valptr = value; + } + else + { + if (value != T ()) + { + // If conversion produces an integer that overflows, failbit is set + // but value is non-zero. We want to treat this case as success, + // so clear failbit from the stream state to keep going. + // FIXME: Maybe set error state on octave stream? Matlab does + // *not* indicate an error message on overflow. + is.clear (status & ~std::ios::failbit); + *valptr = value; + } + else + { + // True error. + // Reset stream to original position, clear eof bit, pass status on. + is.clear (); + is.seekg (pos); + is.setstate (status & ~std::ios_base::eofbit); + } + } return is; } @@ -4433,17 +4447,20 @@ case 'E': case 'G': { - int c1 = std::istream::traits_type::eof (); - - while (is && (c1 = is.get ()) != std::istream::traits_type::eof () - && isspace (c1)) - ; // skip whitespace - - if (c1 != std::istream::traits_type::eof ()) + is >> std::ws; // skip through whitespace and advance stream pointer + if (is.good ()) { - is.putback (c1); + std::streampos pos = is.tellg (); ref = read_value (is); + + std::ios::iostate status = is.rdstate (); + if (status & std::ios::failbit) + { + is.clear (); + is.seekg (pos); + is.setstate (status & ~std::ios_base::eofbit); + } } } break; @@ -4497,11 +4514,16 @@ { \ int c = std::istream::traits_type::eof (); \ \ + /* get all whitespace characters */ \ while (is && (c = is.get ()) != std::istream::traits_type::eof () \ && isspace (c)) \ { /* skip whitespace */ } \ \ - if (c != std::istream::traits_type::eof ()) \ + if (c == std::istream::traits_type::eof ()) \ + /* reset failbit at eof */ \ + is.clear (is.rdstate () & (~std::ios::failbit)); \ + else \ + /* put back non-whitespace character */ \ is.putback (c); \ } \ while (0) @@ -4566,8 +4588,8 @@ && (c = is.get ()) != std::istream::traits_type::eof ()) \ tmp[n++] = static_cast (c); \ \ - if (n > 0 && c == std::istream::traits_type::eof ()) \ - is.clear (); \ + if (c == std::istream::traits_type::eof ()) \ + is.clear (is.rdstate () & (~std::ios::failbit)); \ \ tmp.resize (n) @@ -4609,8 +4631,8 @@ tmp[n++] = static_cast (c); \ } \ \ - if (n > 0 && c == std::istream::traits_type::eof ()) \ - is.clear (); \ + if (c == std::istream::traits_type::eof ()) \ + is.clear (is.rdstate () & (~std::ios::failbit)); \ \ tmp.resize (n); \ } \ @@ -4623,15 +4645,13 @@ // This format must match a nonempty sequence of characters. #define BEGIN_CHAR_CLASS_CONVERSION() \ - int width = elt->width; \ + int width = (elt->width ? elt->width \ + : std::numeric_limits::max ()); \ \ std::string tmp; \ \ do \ { \ - if (! width) \ - width = std::numeric_limits::max (); \ - \ std::ostringstream buf; \ \ std::string char_class = elt->char_class; \ @@ -4642,29 +4662,39 @@ { \ int chars_read = 0; \ while (is && chars_read++ < width \ - && (c = is.get ()) != std::istream::traits_type::eof () \ - && char_class.find (c) != std::string::npos) \ - buf << static_cast (c); \ + && (c = is.get ()) != std::istream::traits_type::eof ()) \ + { \ + if (char_class.find (c) != std::string::npos) \ + buf << static_cast (c); \ + else \ + { \ + is.putback (c); \ + break; \ + } \ + } \ } \ else \ { \ int chars_read = 0; \ while (is && chars_read++ < width \ - && (c = is.get ()) != std::istream::traits_type::eof () \ - && char_class.find (c) == std::string::npos) \ - buf << static_cast (c); \ + && (c = is.get ()) != std::istream::traits_type::eof ()) \ + { \ + if (char_class.find (c) == std::string::npos) \ + buf << static_cast (c); \ + else \ + { \ + is.putback (c); \ + break; \ + } \ + } \ } \ \ - if (width == std::numeric_limits::max () \ - && c != std::istream::traits_type::eof ()) \ - is.putback (c); \ - \ tmp = buf.str (); \ \ if (tmp.empty ()) \ is.setstate (std::ios::failbit); \ else if (c == std::istream::traits_type::eof ()) \ - is.clear (); \ + is.clear (is.rdstate () & (~std::ios::failbit)); \ \ } \ while (0) @@ -4676,7 +4706,7 @@ tmp = string::u8_from_encoding (who, tmp, encoding ()); \ width = tmp.length (); \ \ - if (is) \ + if (is && width > 0) \ { \ int i = 0; \ \ @@ -5048,10 +5078,10 @@ // If it looks like we have a matching failure, then // reset the failbit in the stream state. - if (! is.eof () && is.rdstate () & std::ios::failbit) + if (is.rdstate () & std::ios::failbit) { - error (who, "format failed to match"); is.clear (is.rdstate () & (~std::ios::failbit)); + error (who, "format failed to match"); } // FIXME: is this the right thing to do? diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/oct-strstrm.h --- a/libinterp/corefcn/oct-strstrm.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/oct-strstrm.h Fri Dec 02 10:12:40 2022 -0500 @@ -194,17 +194,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::base_strstream' instead") -typedef octave::base_strstream octave_base_strstream; - -OCTAVE_DEPRECATED (7, "use 'octave::istrstream' instead") -typedef octave::istrstream octave_istrstream; - -OCTAVE_DEPRECATED (7, "use 'octave::ostrstream' instead") -typedef octave::ostrstream octave_ostrstream; - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/procstream.h --- a/libinterp/corefcn/procstream.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/procstream.h Fri Dec 02 10:12:40 2022 -0500 @@ -187,20 +187,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::procstreambase' instead") -typedef octave::procstreambase procstreambase; - -OCTAVE_DEPRECATED (7, "use 'octave::iprocstream' instead") -typedef octave::iprocstream iprocstream; - -OCTAVE_DEPRECATED (7, "use 'octave::oprocstream' instead") -typedef octave::oprocstream oprocstream; - -OCTAVE_DEPRECATED (7, "use 'octave::procstream' instead") -typedef octave::procstream procstream; - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/sparse-xdiv.h --- a/libinterp/corefcn/sparse-xdiv.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/sparse-xdiv.h Fri Dec 02 10:12:40 2022 -0500 @@ -104,207 +104,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline Matrix -xdiv (const Matrix& a, const SparseMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline ComplexMatrix -xdiv (const Matrix& a, const SparseComplexMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline ComplexMatrix -xdiv (const ComplexMatrix& a, const SparseMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline ComplexMatrix -xdiv (const ComplexMatrix& a, const SparseComplexMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline SparseMatrix -xdiv (const SparseMatrix& a, const SparseMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline SparseComplexMatrix -xdiv (const SparseMatrix& a, const SparseComplexMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline SparseComplexMatrix -xdiv (const SparseComplexMatrix& a, const SparseMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline SparseComplexMatrix -xdiv (const SparseComplexMatrix& a, const SparseComplexMatrix& b, - MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline SparseMatrix -xdiv (const SparseMatrix& a, const DiagMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline SparseComplexMatrix -xdiv (const SparseMatrix& a, const ComplexDiagMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline SparseComplexMatrix -xdiv (const SparseComplexMatrix& a, const DiagMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline SparseComplexMatrix -xdiv (const SparseComplexMatrix& a, const ComplexDiagMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline Matrix -x_el_div (double a, const SparseMatrix& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline ComplexMatrix -x_el_div (double a, const SparseComplexMatrix& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline ComplexMatrix -x_el_div (const Complex& a, const SparseMatrix& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline ComplexMatrix -x_el_div (const Complex& a, const SparseComplexMatrix& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline Matrix -xleftdiv (const SparseMatrix& a, const Matrix& b, MatrixType& typ) -{ - return octave::xleftdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline ComplexMatrix -xleftdiv (const SparseMatrix& a, const ComplexMatrix& b, MatrixType& typ) -{ - return octave::xleftdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline ComplexMatrix -xleftdiv (const SparseComplexMatrix& a, const Matrix& b, MatrixType& typ) -{ - return octave::xleftdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline ComplexMatrix -xleftdiv (const SparseComplexMatrix& a, const ComplexMatrix& b, MatrixType& typ) -{ - return octave::xleftdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline SparseMatrix -xleftdiv (const SparseMatrix& a, const SparseMatrix& b, MatrixType& typ) -{ - return octave::xleftdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline SparseComplexMatrix -xleftdiv (const SparseMatrix& a, const SparseComplexMatrix& b, MatrixType& typ) -{ - return octave::xleftdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline SparseComplexMatrix -xleftdiv (const SparseComplexMatrix& a, const SparseMatrix& b, MatrixType& typ) -{ - return octave::xleftdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline SparseComplexMatrix -xleftdiv (const SparseComplexMatrix& a, const SparseComplexMatrix& b, - MatrixType& typ) -{ - return octave::xleftdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline SparseMatrix -xleftdiv (const DiagMatrix& a, const SparseMatrix& b, MatrixType& typ) -{ - return octave::xleftdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline SparseComplexMatrix -xleftdiv (const ComplexDiagMatrix& a, const SparseMatrix& b, MatrixType& typ) -{ - return octave::xleftdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline SparseComplexMatrix -xleftdiv (const DiagMatrix& a, const SparseComplexMatrix& b, MatrixType& typ) -{ - return octave::xleftdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline SparseComplexMatrix -xleftdiv (const ComplexDiagMatrix& a, const SparseComplexMatrix& b, - MatrixType& typ) -{ - return octave::xleftdiv (a, b, typ); -} - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/sparse-xpow.h --- a/libinterp/corefcn/sparse-xpow.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/sparse-xpow.h Fri Dec 02 10:12:40 2022 -0500 @@ -62,106 +62,4 @@ OCTAVE_END_NAMESPACE(octave) -#if (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const SparseMatrix& a, double b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const SparseComplexMatrix& a, double b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (double a, const SparseMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (double a, const SparseComplexMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const SparseMatrix& a, double b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const SparseMatrix& a, const SparseMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const SparseMatrix& a, const Complex& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const SparseMatrix& a, const SparseComplexMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const Complex& a, const SparseMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const Complex& a, const SparseComplexMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const SparseComplexMatrix& a, double b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const SparseComplexMatrix& a, const SparseMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const SparseComplexMatrix& a, const Complex& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const SparseComplexMatrix& a, const SparseComplexMatrix& b) -{ - return octave::elem_xpow (a, b); -} - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/variables.h --- a/libinterp/corefcn/variables.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/variables.h Fri Dec 02 10:12:40 2022 -0500 @@ -107,91 +107,6 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::symbol_exist' instead") -inline int -symbol_exist (const std::string& name, const std::string& type = "any") -{ - return octave::symbol_exist (name, type); -} - -OCTAVE_DEPRECATED (7, "use 'octave::unique_symbol_name' instead") -inline std::string -unique_symbol_name (const std::string& basename) -{ - return octave::unique_symbol_name (basename); -} - -OCTAVE_DEPRECATED (7, "use 'octave::set_internal_variable' instead") -inline octave_value -set_internal_variable (bool& var, const octave_value_list& args, int nargout, - const char *nm) -{ - return octave::set_internal_variable (var, args, nargout, nm); -} - -OCTAVE_DEPRECATED (7, "use 'octave::set_internal_variable' instead") -inline octave_value -set_internal_variable (char& var, const octave_value_list& args, int nargout, - const char *nm) -{ - return octave::set_internal_variable (var, args, nargout, nm); -} - -OCTAVE_DEPRECATED (7, "use 'octave::set_internal_variable' instead") -inline octave_value -set_internal_variable (int& var, const octave_value_list& args, int nargout, - const char *nm, - int minval = std::numeric_limits::min (), - int maxval = std::numeric_limits::max ()) -{ - return octave::set_internal_variable (var, args, nargout, nm, minval, maxval); -} - -OCTAVE_DEPRECATED (7, "use 'octave::set_internal_variable' instead") -inline octave_value -set_internal_variable (double& var, const octave_value_list& args, int nargout, - const char *nm, - double minval = -octave::numeric_limits::Inf (), - double maxval = octave::numeric_limits::Inf ()) -{ - return octave::set_internal_variable (var, args, nargout, nm, minval, maxval); -} - -OCTAVE_DEPRECATED (7, "use 'octave::set_internal_variable' instead") -inline octave_value -set_internal_variable (std::string& var, const octave_value_list& args, - int nargout, const char *nm, bool empty_ok = true) -{ - return octave::set_internal_variable (var, args, nargout, nm, empty_ok); -} - -OCTAVE_DEPRECATED (7, "use 'octave::set_internal_variable' instead") -inline octave_value -set_internal_variable (std::string& var, const octave_value_list& args, - int nargout, const char *nm, const char **choices) -{ - return octave::set_internal_variable (var, args, nargout, nm, choices); -} - -OCTAVE_DEPRECATED (7, "use 'octave::set_internal_variable' instead") -inline octave_value -set_internal_variable (int& var, const octave_value_list& args, int nargout, - const char *nm, const char **choices) -{ - return octave::set_internal_variable (var, args, nargout, nm, choices); -} - -OCTAVE_DEPRECATED (7, "use 'octave::maybe_missing_function_hook' instead") -inline std::string -maybe_missing_function_hook (const std::string& name) -{ - return octave::maybe_missing_function_hook (name); -} - -#endif - // The following macros should also be considered obsolete. #define SET_INTERNAL_VARIABLE(NM) \ diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/xdiv.h --- a/libinterp/corefcn/xdiv.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/xdiv.h Fri Dec 02 10:12:40 2022 -0500 @@ -156,415 +156,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline Matrix -xdiv (const Matrix& a, const Matrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline ComplexMatrix -xdiv (const Matrix& a, const ComplexMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline ComplexMatrix -xdiv (const ComplexMatrix& a, const Matrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline ComplexMatrix -xdiv (const ComplexMatrix& a, const ComplexMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline Matrix -x_el_div (double a, const Matrix& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline ComplexMatrix -x_el_div (double a, const ComplexMatrix& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline ComplexMatrix -x_el_div (const Complex a, const Matrix& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline ComplexMatrix -x_el_div (const Complex a, const ComplexMatrix& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline NDArray -x_el_div (double a, const NDArray& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline ComplexNDArray -x_el_div (double a, const ComplexNDArray& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline ComplexNDArray -x_el_div (const Complex a, const NDArray& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline ComplexNDArray -x_el_div (const Complex a, const ComplexNDArray& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline Matrix -xleftdiv (const Matrix& a, const Matrix& b, - MatrixType& typ, blas_trans_type transt = blas_no_trans) -{ - return octave::xleftdiv (a, b, typ, transt); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline ComplexMatrix -xleftdiv (const Matrix& a, const ComplexMatrix& b, - MatrixType& typ, blas_trans_type transt = blas_no_trans) -{ - return octave::xleftdiv (a, b, typ, transt); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline ComplexMatrix -xleftdiv (const ComplexMatrix& a, const Matrix& b, - MatrixType& typ, blas_trans_type transt = blas_no_trans) -{ - return octave::xleftdiv (a, b, typ, transt); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline ComplexMatrix -xleftdiv (const ComplexMatrix& a, const ComplexMatrix& b, - MatrixType& typ, blas_trans_type transt = blas_no_trans) -{ - return octave::xleftdiv (a, b, typ, transt); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline FloatMatrix -xdiv (const FloatMatrix& a, const FloatMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline FloatComplexMatrix -xdiv (const FloatMatrix& a, const FloatComplexMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline FloatComplexMatrix -xdiv (const FloatComplexMatrix& a, const FloatMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline FloatComplexMatrix -xdiv (const FloatComplexMatrix& a, const FloatComplexMatrix& b, MatrixType& typ) -{ - return octave::xdiv (a, b, typ); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline FloatMatrix -x_el_div (float a, const FloatMatrix& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline FloatComplexMatrix -x_el_div (float a, const FloatComplexMatrix& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline FloatComplexMatrix -x_el_div (const FloatComplex a, const FloatMatrix& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline FloatComplexMatrix -x_el_div (const FloatComplex a, const FloatComplexMatrix& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline FloatNDArray -x_el_div (float a, const FloatNDArray& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline FloatComplexNDArray -x_el_div (float a, const FloatComplexNDArray& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline FloatComplexNDArray -x_el_div (const FloatComplex a, const FloatNDArray& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead") -inline FloatComplexNDArray -x_el_div (const FloatComplex a, const FloatComplexNDArray& b) -{ - return octave::elem_xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline FloatMatrix -xleftdiv (const FloatMatrix& a, const FloatMatrix& b, - MatrixType& typ, blas_trans_type transt = blas_no_trans) -{ - return octave::xleftdiv (a, b, typ, transt); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline FloatComplexMatrix -xleftdiv (const FloatMatrix& a, const FloatComplexMatrix& b, - MatrixType& typ, blas_trans_type transt = blas_no_trans) -{ - return octave::xleftdiv (a, b, typ, transt); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline FloatComplexMatrix -xleftdiv (const FloatComplexMatrix& a, const FloatMatrix& b, - MatrixType& typ, blas_trans_type transt = blas_no_trans) -{ - return octave::xleftdiv (a, b, typ, transt); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline FloatComplexMatrix -xleftdiv (const FloatComplexMatrix& a, const FloatComplexMatrix& b, - MatrixType& typ, blas_trans_type transt = blas_no_trans) -{ - return octave::xleftdiv (a, b, typ, transt); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline Matrix -xdiv (const Matrix& a, const DiagMatrix& b) -{ - return octave::xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline ComplexMatrix -xdiv (const ComplexMatrix& a, const DiagMatrix& b) -{ - return octave::xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline ComplexMatrix -xdiv (const ComplexMatrix& a, const ComplexDiagMatrix& b) -{ - return octave::xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline DiagMatrix -xdiv (const DiagMatrix& a, const DiagMatrix& b) -{ - return octave::xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline ComplexDiagMatrix -xdiv (const ComplexDiagMatrix& a, const DiagMatrix& b) -{ - return octave::xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline ComplexDiagMatrix -xdiv (const ComplexDiagMatrix& a, const ComplexDiagMatrix& b) -{ - return octave::xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline FloatMatrix -xdiv (const FloatMatrix& a, const FloatDiagMatrix& b) -{ - return octave::xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline FloatComplexMatrix -xdiv (const FloatComplexMatrix& a, const FloatDiagMatrix& b) -{ - return octave::xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline FloatComplexMatrix -xdiv (const FloatMatrix& a, const FloatComplexDiagMatrix& b) -{ - return octave::xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline FloatComplexMatrix -xdiv (const FloatComplexMatrix& a, const FloatComplexDiagMatrix& b) -{ - return octave::xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline FloatDiagMatrix -xdiv (const FloatDiagMatrix& a, const FloatDiagMatrix& b) -{ - return octave::xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline FloatComplexDiagMatrix -xdiv (const FloatComplexDiagMatrix& a, const FloatDiagMatrix& b) -{ - return octave::xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead") -inline FloatComplexDiagMatrix -xdiv (const FloatComplexDiagMatrix& a, const FloatComplexDiagMatrix& b) -{ - return octave::xdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline Matrix -xleftdiv (const DiagMatrix& a, const Matrix& b) -{ - return octave::xleftdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline ComplexMatrix -xleftdiv (const DiagMatrix& a, const ComplexMatrix& b) -{ - return octave::xleftdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline ComplexMatrix -xleftdiv (const ComplexDiagMatrix& a, const ComplexMatrix& b) -{ - return octave::xleftdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline DiagMatrix -xleftdiv (const DiagMatrix& a, const DiagMatrix& b) -{ - return octave::xleftdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline ComplexDiagMatrix -xleftdiv (const DiagMatrix& a, const ComplexDiagMatrix& b) -{ - return octave::xleftdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline ComplexDiagMatrix -xleftdiv (const ComplexDiagMatrix& a, const ComplexDiagMatrix& b) -{ - return octave::xleftdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline FloatMatrix -xleftdiv (const FloatDiagMatrix& a, const FloatMatrix& b) -{ - return octave::xleftdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline FloatComplexMatrix -xleftdiv (const FloatDiagMatrix& a, const FloatComplexMatrix& b) -{ - return octave::xleftdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline FloatComplexMatrix -xleftdiv (const FloatComplexDiagMatrix& a, const FloatComplexMatrix& b) -{ - return octave::xleftdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline FloatDiagMatrix -xleftdiv (const FloatDiagMatrix& a, const FloatDiagMatrix& b) -{ - return octave::xleftdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline FloatComplexDiagMatrix -xleftdiv (const FloatDiagMatrix& a, const FloatComplexDiagMatrix& b) -{ - return octave::xleftdiv (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead") -inline FloatComplexDiagMatrix -xleftdiv (const FloatComplexDiagMatrix& a, const FloatComplexDiagMatrix& b) -{ - return octave::xleftdiv (a, b); -} - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/xnorm.h --- a/libinterp/corefcn/xnorm.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/xnorm.h Fri Dec 02 10:12:40 2022 -0500 @@ -48,36 +48,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead") -inline octave_value -xnorm (const octave_value& x, const octave_value& p) -{ - return octave::xnorm (x, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xcolnorms' instead") -inline octave_value -xcolnorms (const octave_value& x, const octave_value& p) -{ - return octave::xcolnorms (x, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xrownorms' instead") -inline octave_value -xrownorms (const octave_value& x, const octave_value& p) -{ - return octave::xrownorms (x, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xfrobnorm' instead") -inline octave_value -xfrobnorm (const octave_value& x) -{ - return octave::xfrobnorm (x); -} - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/corefcn/xpow.h --- a/libinterp/corefcn/xpow.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/corefcn/xpow.h Fri Dec 02 10:12:40 2022 -0500 @@ -44,7 +44,6 @@ class ComplexNDArray; class FloatComplexNDArray; class octave_value; -class Range; OCTAVE_BEGIN_NAMESPACE(octave) @@ -209,589 +208,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (double a, double b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (double a, const Matrix& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (double a, const Complex& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (double a, const ComplexMatrix& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const Matrix& a, double b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const Matrix& a, const Complex& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const DiagMatrix& a, double b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const DiagMatrix& a, const Complex& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const PermMatrix& a, double b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const Complex& a, double b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const Complex& a, const Matrix& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const Complex& a, const Complex& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const Complex& a, const ComplexMatrix& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const ComplexMatrix& a, double b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const ComplexMatrix& a, const Complex& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const ComplexDiagMatrix& a, double b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const ComplexDiagMatrix& a, const Complex& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (double a, const Matrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (double a, const ComplexMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (double a, const octave::range& r) -{ - return octave::elem_xpow (a, r); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const Matrix& a, double b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const Matrix& a, const Matrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const Matrix& a, const Complex& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const Matrix& a, const ComplexMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const Complex& a, const Matrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const Complex& a, const ComplexMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const Complex& a, const octave::range& r) -{ - return octave::elem_xpow (a, r); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const ComplexMatrix& a, double b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const ComplexMatrix& a, const Matrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const ComplexMatrix& a, const Complex& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const ComplexMatrix& a, const ComplexMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (double a, const NDArray& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (double a, const ComplexNDArray& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const NDArray& a, double b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const NDArray& a, const NDArray& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const NDArray& a, const Complex& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const NDArray& a, const ComplexNDArray& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const Complex& a, const NDArray& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const Complex& a, const ComplexNDArray& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const ComplexNDArray& a, double b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const ComplexNDArray& a, const NDArray& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const ComplexNDArray& a, const Complex& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const ComplexNDArray& a, const ComplexNDArray& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (float a, float b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (float a, const FloatMatrix& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (float a, const FloatComplex& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (float a, const FloatComplexMatrix& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const FloatMatrix& a, float b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const FloatMatrix& a, const FloatComplex& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const FloatDiagMatrix& a, float b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const FloatDiagMatrix& a, const FloatComplex& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const FloatComplex& a, float b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const FloatComplex& a, const FloatMatrix& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const FloatComplex& a, const FloatComplex& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const FloatComplex& a, const FloatComplexMatrix& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const FloatComplexMatrix& a, float b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const FloatComplexMatrix& a, const FloatComplex& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const FloatComplexDiagMatrix& a, float b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead") -inline octave_value -xpow (const FloatComplexDiagMatrix& a, const FloatComplex& b) -{ - return octave::xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (float a, const FloatMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (float a, const FloatComplexMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatMatrix& a, float b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatMatrix& a, const FloatMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatMatrix& a, const FloatComplex& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatMatrix& a, const FloatComplexMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatComplex& a, const FloatMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatComplex& a, const FloatComplexMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatComplexMatrix& a, float b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatComplexMatrix& a, const FloatMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatComplexMatrix& a, const FloatComplex& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatComplexMatrix& a, const FloatComplexMatrix& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (float a, const FloatNDArray& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (float a, const FloatComplexNDArray& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatNDArray& a, float b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatNDArray& a, const FloatNDArray& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatNDArray& a, const FloatComplex& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatNDArray& a, const FloatComplexNDArray& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatComplex& a, const FloatNDArray& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatComplex& a, const FloatComplexNDArray& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatComplexNDArray& a, float b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatComplexNDArray& a, const FloatNDArray& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatComplexNDArray& a, const FloatComplex& b) -{ - return octave::elem_xpow (a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead") -inline octave_value -elem_xpow (const FloatComplexNDArray& a, const FloatComplexNDArray& b) -{ - return octave::elem_xpow (a, b); -} - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/mk-builtins.pl --- a/libinterp/mk-builtins.pl Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/mk-builtins.pl Fri Dec 02 10:12:40 2022 -0500 @@ -150,23 +150,6 @@ print "\nOCTAVE_END_NAMESPACE(octave)\n"; - print "\n#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)\n\n"; - - foreach $name (sort (@fcn_names)) - { - print "OCTAVE_DEPRECATED (7, \"use 'octave::$name' instead\") -inline octave_value_list -$name (const octave_value_list& args = octave_value_list (), int nargout = 0) -{ - return octave::$name (args, nargout); -} - -"; - } - - ## end OCTAVE_PROVIDE_DEPRECATED_SYMBOLS block - print "\n\n#endif\n"; - print "\n#endif\n"; } elsif ($make_source) diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/module.mk --- a/libinterp/module.mk Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/module.mk Fri Dec 02 10:12:40 2022 -0500 @@ -176,11 +176,6 @@ LIBINTERP_DEFUN_FILES += \ $(BUILT_IN_DEFUN_FILES) -## FIXME: The following two variables are deprecated and should be removed -## in Octave version 3.12. -DLL_CDEFS = @OCTINTERP_DLL_DEFS@ -DLL_CXXDEFS = @OCTINTERP_DLL_DEFS@ - ## Rules to build test files LIBINTERP_TST_FILES_SRC := $(shell $(SHELL) $(srcdir)/build-aux/find-files-with-tests.sh "$(srcdir)" $(ULT_DIST_SRC) $(DLDFCN_SRC)) diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/octave-value/ov-legacy-range.cc --- a/libinterp/octave-value/ov-legacy-range.cc Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/octave-value/ov-legacy-range.cc Fri Dec 02 10:12:40 2022 -0500 @@ -31,6 +31,7 @@ #include #include +#include "Range.h" #include "lo-ieee.h" #include "lo-utils.h" @@ -49,23 +50,326 @@ #include "ls-hdf5.h" #include "ls-utils.h" -#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif +class +Range +{ +public: + + Range (void) + : m_base (0), m_limit (0), m_inc (0), m_numel (0) + { } + + // Assume range is already properly constructed, so just copy internal + // values. However, we set LIMIT to the computed final value because + // that mimics the behavior of the other Range class constructors that + // reset limit to the computed final value. + + Range (const octave::range& r) + : m_base (r.base ()), m_limit (r.final_value ()), m_inc (r.increment ()), + m_numel (r.numel ()) + { } + + Range (const Range& r) = default; + + Range& operator = (const Range& r) = default; + + ~Range (void) = default; + + Range (double b, double l) + : m_base (b), m_limit (l), m_inc (1), m_numel (numel_internal ()) + { + if (! octave::math::isinf (m_limit)) + m_limit = limit_internal (); + } + + Range (double b, double l, double i) + : m_base (b), m_limit (l), m_inc (i), m_numel (numel_internal ()) + { + if (! octave::math::isinf (m_limit)) + m_limit = limit_internal (); + } + + // The range has a finite number of elements. + bool ok (void) const + { + return (octave::math::isfinite (m_limit) + && (m_numel >= 0 || m_numel == -2)); + } + + double base (void) const { return m_base; } + double limit (void) const { return m_limit; } + double increment (void) const { return m_inc; } + + octave_idx_type numel (void) const { return m_numel; } + + bool all_elements_are_ints (void) const; + + Matrix matrix_value (void) const; + + double min (void) const; + double max (void) const; + +private: + + double m_base; + double m_limit; + double m_inc; + + octave_idx_type m_numel; + + octave_idx_type numel_internal (void) const; + + double limit_internal (void) const; + + void init (void); +}; + +bool +Range::all_elements_are_ints (void) const +{ + // If the base and increment are ints, the final value in the range will also + // be an integer, even if the limit is not. If there is one or fewer + // elements only the base needs to be an integer. + + return (! (octave::math::isnan (m_base) || octave::math::isnan (m_inc)) + && (octave::math::nint_big (m_base) == m_base || m_numel < 1) + && (octave::math::nint_big (m_inc) == m_inc || m_numel <= 1)); +} + +Matrix +Range::matrix_value (void) const +{ + Matrix retval (1, m_numel); + + if (m_numel > 0) + { + // The first element must always be *exactly* the base. + // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment). + retval(0) = m_base; + + double b = m_base; + double increment = m_inc; + for (octave_idx_type i = 1; i < m_numel - 1; i++) + retval.xelem (i) = b + i * increment; + + retval.xelem (m_numel - 1) = m_limit; + } + + return retval; +} + +// NOTE: max and min only return useful values if numel > 0. +// do_minmax_body() in max.cc avoids calling Range::min/max if numel == 0. + +double +Range::min (void) const +{ + double retval = 0.0; + if (m_numel > 0) + { + if (m_inc > 0) + retval = m_base; + else + { + retval = m_base + (m_numel - 1) * m_inc; + + // Require '<=' test. See note in max (). + if (retval <= m_limit) + retval = m_limit; + } + + } + return retval; +} + +double +Range::max (void) const +{ + double retval = 0.0; + if (m_numel > 0) + { + if (m_inc > 0) + { + retval = m_base + (m_numel - 1) * m_inc; + + // On some machines (x86 with extended precision floating point + // arithmetic, for example) it is possible that we can overshoot the + // limit by approximately the machine precision even though we were + // very careful in our calculation of the number of elements. + // Therefore, we clip the result to the limit if it overshoots. + // The test also includes equality (>= m_limit) to have expressions + // such as -5:1:-0 result in a -0 endpoint. + if (retval >= m_limit) + retval = m_limit; + } + else + retval = m_base; + } + return retval; +} + +// C See Knuth, Art Of Computer Programming, Vol. 1, Problem 1.2.4-5. +// C +// C===Tolerant FLOOR function. +// C +// C X - is given as a Double Precision argument to be operated on. +// C It is assumed that X is represented with M mantissa bits. +// C CT - is given as a Comparison Tolerance such that +// C 0.LT.CT.LE.3-SQRT(5)/2. If the relative difference between +// C X and A whole number is less than CT, then TFLOOR is +// C returned as this whole number. By treating the +// C floating-point numbers as a finite ordered set note that +// C the heuristic EPS=2.**(-(M-1)) and CT=3*EPS causes +// C arguments of TFLOOR/TCEIL to be treated as whole numbers +// C if they are exactly whole numbers or are immediately +// C adjacent to whole number representations. Since EPS, the +// C "distance" between floating-point numbers on the unit +// C interval, and M, the number of bits in X'S mantissa, exist +// C on every floating-point computer, TFLOOR/TCEIL are +// C consistently definable on every floating-point computer. +// C +// C For more information see the following references: +// C (1) P. E. Hagerty, "More On Fuzzy Floor And Ceiling," APL QUOTE +// C QUAD 8(4):20-24, June 1978. Note that TFLOOR=FL5. +// C (2) L. M. Breed, "Definitions For Fuzzy Floor And Ceiling", APL +// C QUOTE QUAD 8(3):16-23, March 1978. This paper cites FL1 through +// C FL5, the history of five years of evolutionary development of +// C FL5 - the seven lines of code below - by open collaboration +// C and corroboration of the mathematical-computing community. +// C +// C Penn State University Center for Academic Computing +// C H. D. Knoble - August, 1978. + +static inline double +tfloor (double x, double ct) +{ +// C---------FLOOR(X) is the largest integer algebraically less than +// C or equal to X; that is, the unfuzzy FLOOR function. + +// DINT (X) = X - DMOD (X, 1.0); +// FLOOR (X) = DINT (X) - DMOD (2.0 + DSIGN (1.0, X), 3.0); + +// C---------Hagerty's FL5 function follows... + + double q = 1.0; + + if (x < 0.0) + q = 1.0 - ct; + + double rmax = q / (2.0 - ct); + + double t1 = 1.0 + std::floor (x); + t1 = (ct / q) * (t1 < 0.0 ? -t1 : t1); + t1 = (rmax < t1 ? rmax : t1); + t1 = (ct > t1 ? ct : t1); + t1 = std::floor (x + t1); + + if (x <= 0.0 || (t1 - x) < rmax) + return t1; + else + return t1 - 1.0; +} + +static inline bool +teq (double u, double v, + double ct = 3.0 * std::numeric_limits::epsilon ()) +{ + double tu = std::abs (u); + double tv = std::abs (v); + + return std::abs (u - v) < ((tu > tv ? tu : tv) * ct); +} + +octave_idx_type +Range::numel_internal (void) const +{ + octave_idx_type retval = -1; + + if (! octave::math::isfinite (m_base) || ! octave::math::isfinite (m_inc) + || octave::math::isnan (m_limit)) + retval = -2; + else if (octave::math::isinf (m_limit) + && ((m_inc > 0 && m_limit > 0) + || (m_inc < 0 && m_limit < 0))) + retval = std::numeric_limits::max () - 1; + else if (m_inc == 0 + || (m_limit > m_base && m_inc < 0) + || (m_limit < m_base && m_inc > 0)) + { + retval = 0; + } + else + { + double ct = 3.0 * std::numeric_limits::epsilon (); + + double tmp = tfloor ((m_limit - m_base + m_inc) / m_inc, ct); + + octave_idx_type n_elt = (tmp > 0.0 + ? static_cast (tmp) : 0); + + // If the final element that we would compute for the range is equal to + // the limit of the range, or is an adjacent floating point number, + // accept it. Otherwise, try a range with one fewer element. If that + // fails, try again with one more element. + // + // I'm not sure this is very good, but it seems to work better than just + // using tfloor as above. For example, without it, the expression + // 1.8:0.05:1.9 fails to produce the expected result of [1.8, 1.85, 1.9]. + + if (! teq (m_base + (n_elt - 1) * m_inc, m_limit)) + { + if (teq (m_base + (n_elt - 2) * m_inc, m_limit)) + n_elt--; + else if (teq (m_base + n_elt * m_inc, m_limit)) + n_elt++; + } + + retval = ((n_elt < std::numeric_limits::max ()) + ? n_elt : -1); + } + + return retval; +} + +double +Range::limit_internal (void) const +{ + double new_limit = m_inc > 0 ? max () : min (); + + // If result must be an integer then force the new_limit to be one. + if (all_elements_are_ints ()) + new_limit = std::round (new_limit); + + return new_limit; +} + +void +Range::init (void) +{ + m_numel = numel_internal (); + + if (! octave::math::isinf (m_limit)) + m_limit = limit_internal (); +} DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_legacy_range, "range", "double"); octave_legacy_range::octave_legacy_range (void) - : octave_base_value (), range () { } + : octave_base_value (), m_range (new Range ()) { } octave_legacy_range::octave_legacy_range (const Range& r) - : octave_base_value (), range (r) + : octave_base_value (), m_range (new Range (r)) { - if (range.numel () < 0 && range.numel () != -2) + if (m_range->numel () < 0 && m_range->numel () != -2) error ("invalid range"); } +octave_legacy_range::octave_legacy_range (const octave_legacy_range& r) + : octave_base_value (r), m_range () +{ + m_range.reset (new Range (*(r.m_range))); +} + static octave_base_value * default_numeric_conversion_function (const octave_base_value& a) { @@ -78,7 +382,7 @@ octave_legacy_range::numeric_conversion_function (void) const { return octave_base_value::type_conv_info (default_numeric_conversion_function, - octave_matrix::static_type_id ()); + octave_matrix::static_type_id ()); } octave_base_value * @@ -86,10 +390,10 @@ { octave_base_value *retval = nullptr; - switch (range.numel ()) + switch (m_range->numel ()) { case 1: - retval = new octave_scalar (range.base ()); + retval = new octave_scalar (m_range->base ()); break; case 0: @@ -97,17 +401,17 @@ break; case -2: - retval = new octave_matrix (range.matrix_value ()); + retval = new octave_matrix (m_range->matrix_value ()); break; default: { - if (range.increment () == 0) - retval = new octave_matrix (range.matrix_value ()); + if (m_range->increment () == 0) + retval = new octave_matrix (m_range->matrix_value ()); else retval = new octave_range - (octave::range (range.base (), range.increment (), - range.limit (), range.numel ())); + (octave::range (m_range->base (), m_range->increment (), + m_range->limit (), m_range->numel ())); } break; } @@ -145,9 +449,9 @@ error ("load: failed to load range constant"); if (inc != 0) - range = Range (base, limit, inc); + m_range.reset (new Range (base, limit, inc)); else - range = Range (base, inc, static_cast (limit)); + m_range.reset (new Range (base, inc, static_cast (limit))); return true; } @@ -173,9 +477,9 @@ if (swap) swap_bytes<8> (&inc); if (inc != 0) - range = Range (bas, lim, inc); + m_range.reset (new Range (bas, lim, inc)); else - range = Range (bas, inc, static_cast (lim)); + m_range.reset (new Range (bas, inc, static_cast (lim))); return true; } @@ -245,14 +549,14 @@ octave_idx_type nel; if (hdf5_get_scalar_attr (data_hid, H5T_NATIVE_IDX, "OCTAVE_RANGE_NELEM", &nel)) - range = Range (rangevals[0], rangevals[2], nel); + m_range.reset (new Range (rangevals[0], rangevals[2], nel)); else { if (rangevals[2] != 0) - range = Range (rangevals[0], rangevals[1], rangevals[2]); + m_range.reset (new Range (rangevals[0], rangevals[1], rangevals[2])); else - range = Range (rangevals[0], rangevals[2], - static_cast (rangevals[1])); + m_range.reset (new Range (rangevals[0], rangevals[2], + static_cast (rangevals[1]))); } } @@ -269,7 +573,3 @@ return retval; } - -#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC) -# pragma GCC diagnostic pop -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/octave-value/ov-legacy-range.h --- a/libinterp/octave-value/ov-legacy-range.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/octave-value/ov-legacy-range.h Fri Dec 02 10:12:40 2022 -0500 @@ -31,10 +31,9 @@ #include #include +#include #include -#include "Range.h" - #include "lo-mappers.h" #include "lo-utils.h" #include "mx-base.h" @@ -45,6 +44,8 @@ #include "ov-re-mat.h" #include "ov-typeinfo.h" +class Range; + class octave_value_list; // Legacy Range values. @@ -65,13 +66,13 @@ octave_legacy_range (const Range& r); - octave_legacy_range (const octave_legacy_range& r) = default; + octave_legacy_range (const octave_legacy_range& r); // No assignment. octave_legacy_range& operator = (const octave_legacy_range&) = delete; - ~octave_legacy_range (void) { } + ~octave_legacy_range (void) = default; octave_base_value * clone (void) const { @@ -102,7 +103,7 @@ private: - Range range; + std::unique_ptr m_range; DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA }; diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/octave-value/ov.cc --- a/libinterp/octave-value/ov.cc Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/octave-value/ov.cc Fri Dec 02 10:12:40 2022 -0500 @@ -1073,36 +1073,6 @@ maybe_mutate (); } -// Remove when public constructor that uses this function is removed. -octave_base_value * -octave_value::make_range_rep_deprecated (double base, double inc, double limit) -{ -#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - - return dynamic_cast - (new octave_legacy_range (Range (base, inc, limit))); - -#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC) -# pragma GCC diagnostic pop -#endif -} - -// Remove when public constructor that uses this function is removed. -octave_base_value * -octave_value::make_range_rep_deprecated (const Range& r, bool force_range) -{ - if (! force_range && ! r.ok ()) - error ("invalid range"); - - if ((force_range || Voptimize_range)) - return dynamic_cast (new octave_legacy_range (r)); - else - return dynamic_cast (new octave_matrix (r.matrix_value ())); -} - octave_value::octave_value (const octave::range& r, bool force_range) : m_rep (force_range || Voptimize_range ? dynamic_cast (new ov_range (r)) @@ -1201,8 +1171,8 @@ : m_rep (force_range || optimize_range ? dynamic_cast (new octave_char_range (r, type)) : dynamic_cast (type == '"' - ? new octave_char_matrix_dq_str (r.array_value ()) - : new octave_char_matrix_sq_str (r.array_value ()))) + ? new octave_char_matrix_dq_str (r.array_value ()) + : new octave_char_matrix_sq_str (r.array_value ()))) #else : m_rep (type == '"' ? new octave_char_matrix_dq_str (r.array_value ()) @@ -1891,10 +1861,10 @@ ComplexColumnVector octave_value::complex_column_vector_value (bool force_string_conv, - bool frc_vec_conv) const + bool frc_vec_conv) const { return ComplexColumnVector (complex_vector_value (force_string_conv, - frc_vec_conv)); + frc_vec_conv)); } RowVector @@ -1910,7 +1880,7 @@ bool frc_vec_conv) const { return ComplexRowVector (complex_vector_value (force_string_conv, - frc_vec_conv)); + frc_vec_conv)); } Array @@ -1920,8 +1890,8 @@ Array retval = array_value (force_string_conv); return retval.reshape (make_vector_dims (retval.dims (), - force_vector_conversion, - type_name (), "real vector")); + force_vector_conversion, + type_name (), "real vector")); } template @@ -1989,8 +1959,8 @@ } return retval.reshape (make_vector_dims (retval.dims (), - force_vector_conversion, - type_name (), "integer vector")); + force_vector_conversion, + type_name (), "integer vector")); } template @@ -2008,8 +1978,8 @@ Array octave_value::octave_idx_type_vector_value (bool require_int, - bool force_string_conv, - bool force_vector_conversion) const + bool force_string_conv, + bool force_vector_conversion) const { Array retval; @@ -2059,8 +2029,8 @@ } return retval.reshape (make_vector_dims (retval.dims (), - force_vector_conversion, - type_name (), "integer vector")); + force_vector_conversion, + type_name (), "integer vector")); } Array @@ -2070,25 +2040,25 @@ Array retval = complex_array_value (force_string_conv); return retval.reshape (make_vector_dims (retval.dims (), - force_vector_conversion, - type_name (), "complex vector")); + force_vector_conversion, + type_name (), "complex vector")); } FloatColumnVector octave_value::float_column_vector_value (bool force_string_conv, - bool frc_vec_conv) const + bool frc_vec_conv) const { return FloatColumnVector (float_vector_value (force_string_conv, - frc_vec_conv)); + frc_vec_conv)); } FloatComplexColumnVector octave_value::float_complex_column_vector_value (bool force_string_conv, - bool frc_vec_conv) const + bool frc_vec_conv) const { return FloatComplexColumnVector (float_complex_vector_value (force_string_conv, - frc_vec_conv)); + frc_vec_conv)); } FloatRowVector @@ -2096,15 +2066,15 @@ bool frc_vec_conv) const { return FloatRowVector (float_vector_value (force_string_conv, - frc_vec_conv)); + frc_vec_conv)); } FloatComplexRowVector octave_value::float_complex_row_vector_value (bool force_string_conv, - bool frc_vec_conv) const + bool frc_vec_conv) const { return FloatComplexRowVector (float_complex_vector_value (force_string_conv, - frc_vec_conv)); + frc_vec_conv)); } Array @@ -2114,19 +2084,19 @@ Array retval = float_array_value (force_string_conv); return retval.reshape (make_vector_dims (retval.dims (), - force_vector_conversion, - type_name (), "real vector")); + force_vector_conversion, + type_name (), "real vector")); } Array octave_value::float_complex_vector_value (bool force_string_conv, - bool force_vector_conversion) const + bool force_vector_conversion) const { Array retval = float_complex_array_value (force_string_conv); return retval.reshape (make_vector_dims (retval.dims (), - force_vector_conversion, - type_name (), "complex vector")); + force_vector_conversion, + type_name (), "complex vector")); } // NAME can't always be "x ## FCN" because some of the original @@ -2214,8 +2184,7 @@ XVALUE_EXTRACTOR (DiagMatrix, xdiag_matrix_value, diag_matrix_value) XVALUE_EXTRACTOR (FloatDiagMatrix, xfloat_diag_matrix_value, float_diag_matrix_value) XVALUE_EXTRACTOR (ComplexDiagMatrix, xcomplex_diag_matrix_value, complex_diag_matrix_value) -XVALUE_EXTRACTOR (FloatComplexDiagMatrix, xfloat_complex_diag_matrix_value, - float_complex_diag_matrix_value) +XVALUE_EXTRACTOR (FloatComplexDiagMatrix, xfloat_complex_diag_matrix_value, float_complex_diag_matrix_value) XVALUE_EXTRACTOR (PermMatrix, xperm_matrix_value, perm_matrix_value) @@ -2273,16 +2242,13 @@ XVALUE_EXTRACTOR (ComplexRowVector, xcomplex_row_vector_value, complex_row_vector_value) XVALUE_EXTRACTOR (FloatColumnVector, xfloat_column_vector_value, float_column_vector_value) -XVALUE_EXTRACTOR (FloatComplexColumnVector, xfloat_complex_column_vector_value, - float_complex_column_vector_value) +XVALUE_EXTRACTOR (FloatComplexColumnVector, xfloat_complex_column_vector_value, float_complex_column_vector_value) XVALUE_EXTRACTOR (FloatRowVector, xfloat_row_vector_value, float_row_vector_value) -XVALUE_EXTRACTOR (FloatComplexRowVector, xfloat_complex_row_vector_value, - float_complex_row_vector_value) +XVALUE_EXTRACTOR (FloatComplexRowVector, xfloat_complex_row_vector_value, float_complex_row_vector_value) XVALUE_EXTRACTOR (Array, xint_vector_value, int_vector_value) -XVALUE_EXTRACTOR (Array, xoctave_idx_type_vector_value, - octave_idx_type_vector_value) +XVALUE_EXTRACTOR (Array, xoctave_idx_type_vector_value, octave_idx_type_vector_value) XVALUE_EXTRACTOR (Array, xvector_value, vector_value) XVALUE_EXTRACTOR (Array, xcomplex_vector_value, complex_vector_value) @@ -2520,7 +2486,7 @@ if (! tmp) err_unary_op_conversion_failed - (octave_value::unary_op_as_string (op), type_name ()); + (octave_value::unary_op_as_string (op), type_name ()); octave_base_value *old_rep = m_rep; m_rep = tmp; @@ -2692,950 +2658,950 @@ OCTAVE_BEGIN_NAMESPACE(octave) -OCTAVE_NORETURN static void -err_binary_op (const std::string& on, const std::string& tn1, - const std::string& tn2) -{ - error ("binary operator '%s' not implemented for '%s' by '%s' operations", - on.c_str (), tn1.c_str (), tn2.c_str ()); -} - -OCTAVE_NORETURN static void -err_binary_op_conv (const std::string& on) -{ - error ("type conversion failed for binary operator '%s'", on.c_str ()); -} - -octave_value -binary_op (type_info& ti, octave_value::binary_op op, - const octave_value& v1, const octave_value& v2) -{ - octave_value retval; - - int t1 = v1.type_id (); - int t2 = v2.type_id (); - - if (t1 == octave_class::static_type_id () - || t2 == octave_class::static_type_id () - || t1 == octave_classdef::static_type_id () - || t2 == octave_classdef::static_type_id ()) - { - type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op); - - if (! f) - err_binary_op (octave_value::binary_op_as_string (op), - v1.class_name (), v2.class_name ()); - - retval = f (v1, v2); - } - else - { - // FIXME: we need to handle overloading operators for built-in - // classes (double, char, int8, etc.) - - type_info::binary_op_fcn f - = ti.lookup_binary_op (op, t1, t2); - - if (f) - retval = f (v1.get_rep (), v2.get_rep ()); - else - { - octave_value tv1; - octave_base_value::type_conv_info cf1 - = v1.numeric_conversion_function (); - - octave_value tv2; - octave_base_value::type_conv_info cf2 - = v2.numeric_conversion_function (); - - // Try biased (one-sided) conversions first. - if (cf2.type_id () >= 0 - && ti.lookup_binary_op (op, t1, cf2.type_id ())) - cf1 = nullptr; - else if (cf1.type_id () >= 0 - && ti.lookup_binary_op (op, cf1.type_id (), t2)) - cf2 = nullptr; - - if (cf1) - { - octave_base_value *tmp = cf1 (v1.get_rep ()); - - if (! tmp) - err_binary_op_conv (octave_value::binary_op_as_string (op)); - - tv1 = octave_value (tmp); - t1 = tv1.type_id (); - } - else - tv1 = v1; - - if (cf2) - { - octave_base_value *tmp = cf2 (v2.get_rep ()); - - if (! tmp) - err_binary_op_conv (octave_value::binary_op_as_string (op)); - - tv2 = octave_value (tmp); - t2 = tv2.type_id (); - } - else - tv2 = v2; - - if (cf1 || cf2) - { - retval = binary_op (op, tv1, tv2); - } - else - { - //demote double -> single and try again - cf1 = tv1.numeric_demotion_function (); - - cf2 = tv2.numeric_demotion_function (); - - // Try biased (one-sided) conversions first. - if (cf2.type_id () >= 0 - && ti.lookup_binary_op (op, t1, cf2.type_id ())) - cf1 = nullptr; - else if (cf1.type_id () >= 0 - && ti.lookup_binary_op (op, cf1.type_id (), t2)) - cf2 = nullptr; - - if (cf1) - { - octave_base_value *tmp = cf1 (tv1.get_rep ()); - - if (! tmp) - err_binary_op_conv (octave_value::binary_op_as_string (op)); - - tv1 = octave_value (tmp); - t1 = tv1.type_id (); - } - - if (cf2) - { - octave_base_value *tmp = cf2 (tv2.get_rep ()); - - if (! tmp) - err_binary_op_conv (octave_value::binary_op_as_string (op)); - - tv2 = octave_value (tmp); - t2 = tv2.type_id (); - } - - if (! cf1 && ! cf2) - err_binary_op (octave_value::binary_op_as_string (op), - v1.type_name (), v2.type_name ()); - - f = ti.lookup_binary_op (op, t1, t2); - - if (! f) - err_binary_op (octave_value::binary_op_as_string (op), - v1.type_name (), v2.type_name ()); - - retval = f (tv1.get_rep (), tv2.get_rep ()); - } - } - } - - return retval; -} - -octave_value -binary_op (octave_value::binary_op op, const octave_value& v1, - const octave_value& v2) -{ - type_info& ti = __get_type_info__ (); - - return binary_op (ti, op, v1, v2); -} - -static octave_value -decompose_binary_op (type_info& ti, octave_value::compound_binary_op op, - const octave_value& v1, const octave_value& v2) -{ - switch (op) - { - case octave_value::op_trans_mul: - return binary_op (octave_value::op_mul, - unary_op (octave_value::op_transpose, v1), v2); - - case octave_value::op_mul_trans: - return binary_op (ti, octave_value::op_mul, - v1, unary_op (octave_value::op_transpose, v2)); - - case octave_value::op_herm_mul: - return binary_op (ti, octave_value::op_mul, - unary_op (octave_value::op_hermitian, v1), v2); - - case octave_value::op_mul_herm: - return binary_op (ti, octave_value::op_mul, - v1, unary_op (octave_value::op_hermitian, v2)); - - case octave_value::op_trans_ldiv: - return binary_op (ti, octave_value::op_ldiv, - unary_op (octave_value::op_transpose, v1), v2); - - case octave_value::op_herm_ldiv: - return binary_op (ti, octave_value::op_ldiv, - unary_op (octave_value::op_hermitian, v1), v2); - - case octave_value::op_el_not_and: - return binary_op (ti, octave_value::op_el_and, - unary_op (octave_value::op_not, v1), v2); - - case octave_value::op_el_not_or: - return binary_op (ti, octave_value::op_el_or, - unary_op (octave_value::op_not, v1), v2); - - case octave_value::op_el_and_not: - return binary_op (ti, octave_value::op_el_and, - v1, unary_op (octave_value::op_not, v2)); - - case octave_value::op_el_or_not: - return binary_op (ti, octave_value::op_el_or, - v1, unary_op (octave_value::op_not, v2)); - - default: - error ("invalid compound operator"); - } -} - -octave_value -binary_op (type_info& ti, octave_value::compound_binary_op op, - const octave_value& v1, const octave_value& v2) -{ - octave_value retval; - - int t1 = v1.type_id (); - int t2 = v2.type_id (); - - if (t1 == octave_class::static_type_id () - || t2 == octave_class::static_type_id () - || t1 == octave_classdef::static_type_id () - || t2 == octave_classdef::static_type_id ()) - { - type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op); - - if (f) + OCTAVE_NORETURN static void + err_binary_op (const std::string& on, const std::string& tn1, + const std::string& tn2) + { + error ("binary operator '%s' not implemented for '%s' by '%s' operations", + on.c_str (), tn1.c_str (), tn2.c_str ()); + } + + OCTAVE_NORETURN static void + err_binary_op_conv (const std::string& on) + { + error ("type conversion failed for binary operator '%s'", on.c_str ()); + } + + octave_value + binary_op (type_info& ti, octave_value::binary_op op, + const octave_value& v1, const octave_value& v2) + { + octave_value retval; + + int t1 = v1.type_id (); + int t2 = v2.type_id (); + + if (t1 == octave_class::static_type_id () + || t2 == octave_class::static_type_id () + || t1 == octave_classdef::static_type_id () + || t2 == octave_classdef::static_type_id ()) + { + type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op); + + if (! f) + err_binary_op (octave_value::binary_op_as_string (op), + v1.class_name (), v2.class_name ()); + retval = f (v1, v2); - else - retval = decompose_binary_op (ti, op, v1, v2); - } - else - { - type_info::binary_op_fcn f = ti.lookup_binary_op (op, t1, t2); - - if (f) - retval = f (v1.get_rep (), v2.get_rep ()); - else - retval = decompose_binary_op (ti, op, v1, v2); - } - - return retval; -} - -octave_value -binary_op (octave_value::compound_binary_op op, - const octave_value& v1, const octave_value& v2) -{ - type_info& ti = __get_type_info__ (); - - return binary_op (ti, op, v1, v2); -} - -OCTAVE_NORETURN static void -err_cat_op (const std::string& tn1, const std::string& tn2) -{ - error ("concatenation operator not implemented for '%s' by '%s' operations", - tn1.c_str (), tn2.c_str ()); -} - -OCTAVE_NORETURN static void -err_cat_op_conv (void) -{ - error ("type conversion failed for concatenation operator"); -} - -octave_value -cat_op (type_info& ti, const octave_value& v1, - const octave_value& v2, const Array& ra_idx) -{ - octave_value retval; - - // Can't rapid return for concatenation with an empty object here as - // something like cat(1,[],single([]) must return the correct type. - - int t1 = v1.type_id (); - int t2 = v2.type_id (); - - type_info::cat_op_fcn f = ti.lookup_cat_op (t1, t2); - - if (f) - retval = f (v1.get_rep (), v2.get_rep (), ra_idx); - else - { - octave_value tv1; - octave_base_value::type_conv_info cf1 = v1.numeric_conversion_function (); - - octave_value tv2; - octave_base_value::type_conv_info cf2 = v2.numeric_conversion_function (); - - // Try biased (one-sided) conversions first. - if (cf2.type_id () >= 0 && ti.lookup_cat_op (t1, cf2.type_id ())) - cf1 = nullptr; - else if (cf1.type_id () >= 0 && ti.lookup_cat_op (cf1.type_id (), t2)) - cf2 = nullptr; - - if (cf1) - { - octave_base_value *tmp = cf1 (v1.get_rep ()); - - if (! tmp) - err_cat_op_conv (); - - tv1 = octave_value (tmp); - t1 = tv1.type_id (); - } - else - tv1 = v1; - - if (cf2) - { - octave_base_value *tmp = cf2 (v2.get_rep ()); - - if (! tmp) - err_cat_op_conv (); - - tv2 = octave_value (tmp); - t2 = tv2.type_id (); - } - else - tv2 = v2; - - if (! cf1 && ! cf2) - err_cat_op (v1.type_name (), v2.type_name ()); - - retval = cat_op (ti, tv1, tv2, ra_idx); - } - - return retval; -} - -octave_value -cat_op (const octave_value& v1, const octave_value& v2, - const Array& ra_idx) -{ - type_info& ti = __get_type_info__ (); - - return cat_op (ti, v1, v2, ra_idx); -} - -// Unless the colon operator is used with a class or classdef object, -// then all arguments must be the same type or mixed with double -// values. - -static builtin_type_t -get_colon_op_type (builtin_type_t op1_type, builtin_type_t op2_type) -{ - if (op1_type == op2_type) - return op1_type; - - if (op1_type == btyp_double) - return op2_type; - - if (op2_type == btyp_double) - return op1_type; - - return btyp_unknown; -} - -static builtin_type_t -get_colon_op_type (const octave_value& base, const octave_value& increment, + } + else + { + // FIXME: we need to handle overloading operators for built-in + // classes (double, char, int8, etc.) + + type_info::binary_op_fcn f + = ti.lookup_binary_op (op, t1, t2); + + if (f) + retval = f (v1.get_rep (), v2.get_rep ()); + else + { + octave_value tv1; + octave_base_value::type_conv_info cf1 + = v1.numeric_conversion_function (); + + octave_value tv2; + octave_base_value::type_conv_info cf2 + = v2.numeric_conversion_function (); + + // Try biased (one-sided) conversions first. + if (cf2.type_id () >= 0 + && ti.lookup_binary_op (op, t1, cf2.type_id ())) + cf1 = nullptr; + else if (cf1.type_id () >= 0 + && ti.lookup_binary_op (op, cf1.type_id (), t2)) + cf2 = nullptr; + + if (cf1) + { + octave_base_value *tmp = cf1 (v1.get_rep ()); + + if (! tmp) + err_binary_op_conv (octave_value::binary_op_as_string (op)); + + tv1 = octave_value (tmp); + t1 = tv1.type_id (); + } + else + tv1 = v1; + + if (cf2) + { + octave_base_value *tmp = cf2 (v2.get_rep ()); + + if (! tmp) + err_binary_op_conv (octave_value::binary_op_as_string (op)); + + tv2 = octave_value (tmp); + t2 = tv2.type_id (); + } + else + tv2 = v2; + + if (cf1 || cf2) + { + retval = binary_op (op, tv1, tv2); + } + else + { + //demote double -> single and try again + cf1 = tv1.numeric_demotion_function (); + + cf2 = tv2.numeric_demotion_function (); + + // Try biased (one-sided) conversions first. + if (cf2.type_id () >= 0 + && ti.lookup_binary_op (op, t1, cf2.type_id ())) + cf1 = nullptr; + else if (cf1.type_id () >= 0 + && ti.lookup_binary_op (op, cf1.type_id (), t2)) + cf2 = nullptr; + + if (cf1) + { + octave_base_value *tmp = cf1 (tv1.get_rep ()); + + if (! tmp) + err_binary_op_conv (octave_value::binary_op_as_string (op)); + + tv1 = octave_value (tmp); + t1 = tv1.type_id (); + } + + if (cf2) + { + octave_base_value *tmp = cf2 (tv2.get_rep ()); + + if (! tmp) + err_binary_op_conv (octave_value::binary_op_as_string (op)); + + tv2 = octave_value (tmp); + t2 = tv2.type_id (); + } + + if (! cf1 && ! cf2) + err_binary_op (octave_value::binary_op_as_string (op), + v1.type_name (), v2.type_name ()); + + f = ti.lookup_binary_op (op, t1, t2); + + if (! f) + err_binary_op (octave_value::binary_op_as_string (op), + v1.type_name (), v2.type_name ()); + + retval = f (tv1.get_rep (), tv2.get_rep ()); + } + } + } + + return retval; + } + + octave_value + binary_op (octave_value::binary_op op, const octave_value& v1, + const octave_value& v2) + { + type_info& ti = __get_type_info__ (); + + return binary_op (ti, op, v1, v2); + } + + static octave_value + decompose_binary_op (type_info& ti, octave_value::compound_binary_op op, + const octave_value& v1, const octave_value& v2) + { + switch (op) + { + case octave_value::op_trans_mul: + return binary_op (octave_value::op_mul, + unary_op (octave_value::op_transpose, v1), v2); + + case octave_value::op_mul_trans: + return binary_op (ti, octave_value::op_mul, + v1, unary_op (octave_value::op_transpose, v2)); + + case octave_value::op_herm_mul: + return binary_op (ti, octave_value::op_mul, + unary_op (octave_value::op_hermitian, v1), v2); + + case octave_value::op_mul_herm: + return binary_op (ti, octave_value::op_mul, + v1, unary_op (octave_value::op_hermitian, v2)); + + case octave_value::op_trans_ldiv: + return binary_op (ti, octave_value::op_ldiv, + unary_op (octave_value::op_transpose, v1), v2); + + case octave_value::op_herm_ldiv: + return binary_op (ti, octave_value::op_ldiv, + unary_op (octave_value::op_hermitian, v1), v2); + + case octave_value::op_el_not_and: + return binary_op (ti, octave_value::op_el_and, + unary_op (octave_value::op_not, v1), v2); + + case octave_value::op_el_not_or: + return binary_op (ti, octave_value::op_el_or, + unary_op (octave_value::op_not, v1), v2); + + case octave_value::op_el_and_not: + return binary_op (ti, octave_value::op_el_and, + v1, unary_op (octave_value::op_not, v2)); + + case octave_value::op_el_or_not: + return binary_op (ti, octave_value::op_el_or, + v1, unary_op (octave_value::op_not, v2)); + + default: + error ("invalid compound operator"); + } + } + + octave_value + binary_op (type_info& ti, octave_value::compound_binary_op op, + const octave_value& v1, const octave_value& v2) + { + octave_value retval; + + int t1 = v1.type_id (); + int t2 = v2.type_id (); + + if (t1 == octave_class::static_type_id () + || t2 == octave_class::static_type_id () + || t1 == octave_classdef::static_type_id () + || t2 == octave_classdef::static_type_id ()) + { + type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op); + + if (f) + retval = f (v1, v2); + else + retval = decompose_binary_op (ti, op, v1, v2); + } + else + { + type_info::binary_op_fcn f = ti.lookup_binary_op (op, t1, t2); + + if (f) + retval = f (v1.get_rep (), v2.get_rep ()); + else + retval = decompose_binary_op (ti, op, v1, v2); + } + + return retval; + } + + octave_value + binary_op (octave_value::compound_binary_op op, + const octave_value& v1, const octave_value& v2) + { + type_info& ti = __get_type_info__ (); + + return binary_op (ti, op, v1, v2); + } + + OCTAVE_NORETURN static void + err_cat_op (const std::string& tn1, const std::string& tn2) + { + error ("concatenation operator not implemented for '%s' by '%s' operations", + tn1.c_str (), tn2.c_str ()); + } + + OCTAVE_NORETURN static void + err_cat_op_conv (void) + { + error ("type conversion failed for concatenation operator"); + } + + octave_value + cat_op (type_info& ti, const octave_value& v1, + const octave_value& v2, const Array& ra_idx) + { + octave_value retval; + + // Can't rapid return for concatenation with an empty object here as + // something like cat(1,[],single([]) must return the correct type. + + int t1 = v1.type_id (); + int t2 = v2.type_id (); + + type_info::cat_op_fcn f = ti.lookup_cat_op (t1, t2); + + if (f) + retval = f (v1.get_rep (), v2.get_rep (), ra_idx); + else + { + octave_value tv1; + octave_base_value::type_conv_info cf1 = v1.numeric_conversion_function (); + + octave_value tv2; + octave_base_value::type_conv_info cf2 = v2.numeric_conversion_function (); + + // Try biased (one-sided) conversions first. + if (cf2.type_id () >= 0 && ti.lookup_cat_op (t1, cf2.type_id ())) + cf1 = nullptr; + else if (cf1.type_id () >= 0 && ti.lookup_cat_op (cf1.type_id (), t2)) + cf2 = nullptr; + + if (cf1) + { + octave_base_value *tmp = cf1 (v1.get_rep ()); + + if (! tmp) + err_cat_op_conv (); + + tv1 = octave_value (tmp); + t1 = tv1.type_id (); + } + else + tv1 = v1; + + if (cf2) + { + octave_base_value *tmp = cf2 (v2.get_rep ()); + + if (! tmp) + err_cat_op_conv (); + + tv2 = octave_value (tmp); + t2 = tv2.type_id (); + } + else + tv2 = v2; + + if (! cf1 && ! cf2) + err_cat_op (v1.type_name (), v2.type_name ()); + + retval = cat_op (ti, tv1, tv2, ra_idx); + } + + return retval; + } + + octave_value + cat_op (const octave_value& v1, const octave_value& v2, + const Array& ra_idx) + { + type_info& ti = __get_type_info__ (); + + return cat_op (ti, v1, v2, ra_idx); + } + + // Unless the colon operator is used with a class or classdef object, + // then all arguments must be the same type or mixed with double + // values. + + static builtin_type_t + get_colon_op_type (builtin_type_t op1_type, builtin_type_t op2_type) + { + if (op1_type == op2_type) + return op1_type; + + if (op1_type == btyp_double) + return op2_type; + + if (op2_type == btyp_double) + return op1_type; + + return btyp_unknown; + } + + static builtin_type_t + get_colon_op_type (const octave_value& base, const octave_value& increment, + const octave_value& limit) + { + builtin_type_t typ + = get_colon_op_type (base.builtin_type (), increment.builtin_type ()); + + if (typ == btyp_unknown) + return typ; + + return get_colon_op_type (typ, limit.builtin_type ()); + } + + // This check depends on the type of VAL either being the expected + // integer type or a double value. + + template + static void + check_colon_operand (const octave_value& val, const char *op_str) + { + if (! val.is_double_type ()) + return; + + double dval = val.double_value (); + double intpart; + static const double out_of_range_top + = static_cast (std::numeric_limits::max ()) + + 1.; + + if (dval >= out_of_range_top + || dval < std::numeric_limits::min () + || std::modf (dval, &intpart) != 0.0) + error ("colon operator %s invalid (not an integer or out of range for given integer type)", op_str); + } + + // Return the difference between two unsigned integers as an unsigned + // integer of the same type. + + template ::value + && std::is_unsigned::value), + bool>::type = true> + UT + integer_difference (UT a, UT b) + { + return a > b ? a - b : b - a; + } + + // Return the difference between two signed integers as an unsigned + // integer corresponding to the signed type. + + template ::type, + typename std::enable_if<(std::is_integral::value + && std::is_signed::value), + bool>::type = true> + UT + integer_difference (ST a, ST b) + { + // Map to unsigned. + // Idea from https://stackoverflow.com/questions/10589559 + + static const UT offset + = UT (0) - static_cast (std::numeric_limits::min ()); + + UT au = static_cast (a) + offset; + UT bu = static_cast (b) + offset; + + return integer_difference (au, bu); + } + + // Number of elements in an integer range taking care to avoid + // overflow. Base and limit are of the same type. If they are + // unsigned, then increment is also of the same type. If they are + // signed, then the type of increment is the unsigned type + // corresponding to T. Assumes that the base and limit values are + // consistent with the sign of the original increment (not an empty + // range) so we can calculate numel with the absolute value of the + // increment and the absolute difference between the base and limit + // values. + + template ::type, + typename std::enable_if::value, + bool>::type = true> + octave_idx_type + range_numel_aux (T base, UT unsigned_increment, T limit) + { + // Adding one to DIFF/INCREMENT may overflow, so check whether it is + // out of range before adding. + + UT nel_m1 = integer_difference (limit, base) / unsigned_increment; + + // FIXME: fix error message. + if (nel_m1 > std::numeric_limits::max () - 1) + error ("too many elements for range!"); + + return static_cast (nel_m1) + 1; + } + + // Convert signed range increment to unsigned. + + template ::type, + typename std::enable_if<(std::is_integral::value + && std::is_signed::value), + bool>::type = true> + UT + range_increment (ST increment) + { + return (increment < 0 + ? UT (0) - static_cast (increment) + : static_cast (increment)); + } + + // "Convert" unsigned range increment to unsigned. A no-op, but + // needed to provide a consistent interface for other template + // functions. + + template ::type, + typename std::enable_if<(std::is_integral::value + && std::is_unsigned::value), + bool>::type = true> + UT + range_increment (UT increment) + { + return increment; + } + + // Convert double range increment to unsigned. Enable by return type. + + template ::type> + typename std::enable_if<(std::is_integral::value + && std::is_unsigned::value), UT>::type + range_increment (double increment) + { + double abs_increment = std::abs (increment); + + return static_cast (abs_increment); + } + + // Number of elements in an integer range base:increment:limit. Base, + // increment, and limit are of the same signed type. + + template ::value + && std::is_signed::value), + bool>::type = true> + octave_idx_type + range_numel (ST base, ST increment, ST limit) + { + typedef typename std::make_unsigned::type UT; + + if (increment == 0 + || (increment > 0 && base > limit) + || (increment < 0 && base < limit)) + return 0; + + UT unsigned_increment = range_increment (increment); + + return range_numel_aux (base, unsigned_increment, limit); + } + + // Number of elements in an integer range base:increment:limit. Base, + // increment, and limit are unsigned and of the same type. + + template ::value + && std::is_unsigned::value), + bool>::type = true> + octave_idx_type + range_numel (UT base, UT increment, UT limit) + { + // Unsigned, INCREMENT is always >= 0. + if (increment == 0 || base > limit) + return 0; + + return range_numel_aux (base, increment, limit); + } + + // Number of elements in an integer range base:increment:limit. Base + // and limit are of the same type and increment is a double value. + + template ::type, + typename std::enable_if::value, + bool>::type = true> + octave_idx_type + range_numel (T base, double increment, T limit) + { + double intpart; + if (math::isnan (increment) || std::modf (increment, &intpart) != 0.0) + error ("colon operator increment invalid (not an integer)"); + + if (increment == 0 + || (increment > 0 && base > limit) + || (increment < 0 && base < limit)) + return 0; + + static const double out_of_range_top + = static_cast (std::numeric_limits::max ()) + 1.; + + double abs_increment = std::abs (increment); + + // Technically, this condition should be + // `abs_increment > std::numeric_limits::max ()`. + // But intmax('uint64') is not representable exactly as floating point + // number. Instead, it "rounds" up by 1 to 2^64. To account for + // this, use the following expression which works for all unsigned + // integer types. + if (abs_increment >= out_of_range_top) + return 1; + + UT unsigned_increment = range_increment (increment); + + return range_numel_aux (base, unsigned_increment, limit); + } + + // Make a range from integer values. Increment may be integer or double. + + template ::value + && std::is_arithmetic::value), + bool>::type = true> + octave_value + make_int_range (T base, IT increment, T limit) + { + octave_idx_type nel = range_numel (base, increment, limit); + + // For now, we create arrays instead of range for all types + // except double. + + Array> result (dim_vector (1, nel)); + + if (nel > 0) + { + typedef typename std::make_unsigned::type UT; + + UT unsigned_increment = range_increment (increment); + + T val = base; + result.xelem (0) = val; + + if (limit > base) + { + for (octave_idx_type i = 1; i < nel; i++) + { + val += unsigned_increment; + result.xelem (i) = val; + } + } + else + { + for (octave_idx_type i = 1; i < nel; i++) + { + val -= unsigned_increment; + result.xelem (i) = val; + } + } + } + + return octave_value (result); + } + + // Make a range from floating point values. + + // FIXME: Try again to define memory efficient range classes for + // integer and floating point values? Maybe with the templates + // defined in this file we could do that in a reasonable way? + // Regardless of that, it might be good to provide special treatment + // of colon expressions in FOR loops so that we can eliminate the + // "is_for_cmd_expr / force_range" flag from the parser and the + // octave_value constructors for range objects. + + // NOTE: We define this function separately for float and double so + // that we can avoid having to instantiate ov_range. We DO + // instantiate range but only so we can take advantage of the + // range class to generate the corresponding array of float values + // and not have to duplicate that code here. + + template ::value, + bool>::type = true> + octave_value + make_float_range (T base, T increment, T limit, bool is_for_cmd_expr) + { + if (math::isnan (base) + || math::isnan (increment) + || math::isnan (limit)) + return octave_value (numeric_limits::NaN ()); + + if (increment == 0 + || (increment > 0 && base > limit) + || (increment < 0 && base < limit)) + return octave_value (Array (dim_vector (1, 0))); + + // At this point, we know that the base and limit values are + // consistent with the sign of the increment (not an empty range). + + range r (base, increment, limit); + + if (! is_for_cmd_expr && ! r.is_storable ()) + error ("range with infinite number of elements cannot be stored"); + + return octave_value (r, is_for_cmd_expr); + } + + template ::value, + bool>::type = true> + octave_value + make_float_range (T base, T increment, T limit, bool is_for_cmd_expr) + { + if (math::isnan (base) + || math::isnan (increment) + || math::isnan (limit)) + return octave_value (numeric_limits::NaN ()); + + if (increment == 0 + || (increment > 0 && base > limit) + || (increment < 0 && base < limit)) + return octave_value (Array (dim_vector (1, 0))); + + // At this point, we know that the base and limit values are + // consistent with the sign of the increment (not an empty range). + + range r (base, increment, limit); + + if (! is_for_cmd_expr && ! r.is_storable ()) + error ("range with infinite number of elements cannot be stored"); + + return octave_value (r.array_value ()); + } + + template ::value + || std::is_same::value + || std::is_same::value + || std::is_same::value + || std::is_same::value + || std::is_same::value + || std::is_same::value + || std::is_same::value), + bool>::type = true> + octave_value + make_int_range (const octave_value& base, const octave_value& increment, + const octave_value& limit) + { + if (base.isempty () || increment.isempty () || limit.isempty ()) + return octave_value (Array (dim_vector (1, 0))); + + check_colon_operand (base, "lower bound"); + check_colon_operand (limit, "upper bound"); + + typename T::val_type base_val = octave_value_extract (base).value (); + typename T::val_type limit_val = octave_value_extract (limit).value (); + + if (increment.is_double_type ()) + { + double increment_val = increment.double_value (); + + return make_int_range (base_val, increment_val, limit_val); + } + + check_colon_operand (increment, "increment"); + + typename T::val_type increment_val + = octave_value_extract (increment).value (); + + return make_int_range (base_val, increment_val, limit_val); + } + + template ::value, + bool>::type = true> + octave_value + make_float_range (const octave_value& base, const octave_value& increment, + const octave_value& limit, bool is_for_cmd_expr) + { + if (base.isempty () || increment.isempty () || limit.isempty ()) + return octave_value (Array (dim_vector (1, 0))); + + T base_val = octave_value_extract (base); + T increment_val = octave_value_extract (increment); + T limit_val = octave_value_extract (limit); + + return make_float_range (base_val, increment_val, limit_val, + is_for_cmd_expr); + } + + + octave_value + make_char_range (const octave_value& base, const octave_value& increment, const octave_value& limit) -{ - builtin_type_t typ - = get_colon_op_type (base.builtin_type (), increment.builtin_type ()); - - if (typ == btyp_unknown) - return typ; - - return get_colon_op_type (typ, limit.builtin_type ()); -} - -// This check depends on the type of VAL either being the expected -// integer type or a double value. - -template -static void -check_colon_operand (const octave_value& val, const char *op_str) -{ - if (! val.is_double_type ()) - return; - - double dval = val.double_value (); - double intpart; - static const double out_of_range_top - = static_cast (std::numeric_limits::max ()) - + 1.; - - if (dval >= out_of_range_top - || dval < std::numeric_limits::min () - || std::modf (dval, &intpart) != 0.0) - error ("colon operator %s invalid (not an integer or out of range for given integer type)", op_str); -} - -// Return the difference between two unsigned integers as an unsigned -// integer of the same type. - -template ::value - && std::is_unsigned::value), - bool>::type = true> -UT -integer_difference (UT a, UT b) -{ - return a > b ? a - b : b - a; -} - -// Return the difference between two signed integers as an unsigned -// integer corresponding to the signed type. - -template ::type, - typename std::enable_if<(std::is_integral::value - && std::is_signed::value), - bool>::type = true> -UT -integer_difference (ST a, ST b) -{ - // Map to unsigned. - // Idea from https://stackoverflow.com/questions/10589559 - - static const UT offset - = UT (0) - static_cast (std::numeric_limits::min ()); - - UT au = static_cast (a) + offset; - UT bu = static_cast (b) + offset; - - return integer_difference (au, bu); -} - -// Number of elements in an integer range taking care to avoid -// overflow. Base and limit are of the same type. If they are -// unsigned, then increment is also of the same type. If they are -// signed, then the type of increment is the unsigned type -// corresponding to T. Assumes that the base and limit values are -// consistent with the sign of the original increment (not an empty -// range) so we can calculate numel with the absolute value of the -// increment and the absolute difference between the base and limit -// values. - -template ::type, - typename std::enable_if::value, - bool>::type = true> -octave_idx_type -range_numel_aux (T base, UT unsigned_increment, T limit) -{ - // Adding one to DIFF/INCREMENT may overflow, so check whether it is - // out of range before adding. - - UT nel_m1 = integer_difference (limit, base) / unsigned_increment; - - // FIXME: fix error message. - if (nel_m1 > std::numeric_limits::max () - 1) - error ("too many elements for range!"); - - return static_cast (nel_m1) + 1; -} - -// Convert signed range increment to unsigned. - -template ::type, - typename std::enable_if<(std::is_integral::value - && std::is_signed::value), - bool>::type = true> -UT -range_increment (ST increment) -{ - return (increment < 0 - ? UT (0) - static_cast (increment) - : static_cast (increment)); -} - -// "Convert" unsigned range increment to unsigned. A no-op, but -// needed to provide a consistent interface for other template -// functions. - -template ::type, - typename std::enable_if<(std::is_integral::value - && std::is_unsigned::value), - bool>::type = true> -UT -range_increment (UT increment) -{ - return increment; -} - -// Convert double range increment to unsigned. Enable by return type. - -template ::type> -typename std::enable_if<(std::is_integral::value - && std::is_unsigned::value), UT>::type -range_increment (double increment) -{ - double abs_increment = std::abs (increment); - - return static_cast (abs_increment); -} - -// Number of elements in an integer range base:increment:limit. Base, -// increment, and limit are of the same signed type. - -template ::value - && std::is_signed::value), - bool>::type = true> -octave_idx_type -range_numel (ST base, ST increment, ST limit) -{ - typedef typename std::make_unsigned::type UT; - - if (increment == 0 - || (increment > 0 && base > limit) - || (increment < 0 && base < limit)) - return 0; - - UT unsigned_increment = range_increment (increment); - - return range_numel_aux (base, unsigned_increment, limit); -} - -// Number of elements in an integer range base:increment:limit. Base, -// increment, and limit are unsigned and of the same type. - -template ::value - && std::is_unsigned::value), - bool>::type = true> -octave_idx_type -range_numel (UT base, UT increment, UT limit) -{ - // Unsigned, INCREMENT is always >= 0. - if (increment == 0 || base > limit) - return 0; - - return range_numel_aux (base, increment, limit); -} - -// Number of elements in an integer range base:increment:limit. Base -// and limit are of the same type and increment is a double value. - -template ::type, - typename std::enable_if::value, - bool>::type = true> -octave_idx_type -range_numel (T base, double increment, T limit) -{ - double intpart; - if (math::isnan (increment) || std::modf (increment, &intpart) != 0.0) - error ("colon operator increment invalid (not an integer)"); - - if (increment == 0 - || (increment > 0 && base > limit) - || (increment < 0 && base < limit)) - return 0; - - static const double out_of_range_top - = static_cast (std::numeric_limits::max ()) + 1.; - - double abs_increment = std::abs (increment); - - // Technically, this condition should be - // `abs_increment > std::numeric_limits::max ()`. - // But intmax('uint64') is not representable exactly as floating point - // number. Instead, it "rounds" up by 1 to 2^64. To account for - // this, use the following expression which works for all unsigned - // integer types. - if (abs_increment >= out_of_range_top) - return 1; - - UT unsigned_increment = range_increment (increment); - - return range_numel_aux (base, unsigned_increment, limit); -} - -// Make a range from integer values. Increment may be integer or double. - -template ::value - && std::is_arithmetic::value), - bool>::type = true> -octave_value -make_int_range (T base, IT increment, T limit) -{ - octave_idx_type nel = range_numel (base, increment, limit); - - // For now, we create arrays instead of range for all types - // except double. - - Array> result (dim_vector (1, nel)); - - if (nel > 0) - { - typedef typename std::make_unsigned::type UT; - - UT unsigned_increment = range_increment (increment); - - T val = base; - result.xelem (0) = val; - - if (limit > base) - { - for (octave_idx_type i = 1; i < nel; i++) - { - val += unsigned_increment; - result.xelem (i) = val; - } - } - else - { - for (octave_idx_type i = 1; i < nel; i++) - { - val -= unsigned_increment; - result.xelem (i) = val; - } - } - } - - return octave_value (result); -} - -// Make a range from floating point values. - -// FIXME: Try again to define memory efficient range classes for -// integer and floating point values? Maybe with the templates -// defined in this file we could do that in a reasonable way? -// Regardless of that, it might be good to provide special treatment -// of colon expressions in FOR loops so that we can eliminate the -// "is_for_cmd_expr / force_range" flag from the parser and the -// octave_value constructors for range objects. - -// NOTE: We define this function separately for float and double so -// that we can avoid having to instantiate ov_range. We DO -// instantiate range but only so we can take advantage of the -// range class to generate the corresponding array of float values -// and not have to duplicate that code here. - -template ::value, - bool>::type = true> -octave_value -make_float_range (T base, T increment, T limit, bool is_for_cmd_expr) -{ - if (math::isnan (base) - || math::isnan (increment) - || math::isnan (limit)) - return octave_value (numeric_limits::NaN ()); - - if (increment == 0 - || (increment > 0 && base > limit) - || (increment < 0 && base < limit)) - return octave_value (Array (dim_vector (1, 0))); - - // At this point, we know that the base and limit values are - // consistent with the sign of the increment (not an empty range). - - range r (base, increment, limit); - - if (! is_for_cmd_expr && ! r.is_storable ()) - error ("range with infinite number of elements cannot be stored"); - - return octave_value (r, is_for_cmd_expr); -} - -template ::value, - bool>::type = true> -octave_value -make_float_range (T base, T increment, T limit, bool is_for_cmd_expr) -{ - if (math::isnan (base) - || math::isnan (increment) - || math::isnan (limit)) - return octave_value (numeric_limits::NaN ()); - - if (increment == 0 - || (increment > 0 && base > limit) - || (increment < 0 && base < limit)) - return octave_value (Array (dim_vector (1, 0))); - - // At this point, we know that the base and limit values are - // consistent with the sign of the increment (not an empty range). - - range r (base, increment, limit); - - if (! is_for_cmd_expr && ! r.is_storable ()) - error ("range with infinite number of elements cannot be stored"); - - return octave_value (r.array_value ()); -} - -template ::value - || std::is_same::value - || std::is_same::value - || std::is_same::value - || std::is_same::value - || std::is_same::value - || std::is_same::value - || std::is_same::value), - bool>::type = true> -octave_value -make_int_range (const octave_value& base, const octave_value& increment, - const octave_value& limit) -{ - if (base.isempty () || increment.isempty () || limit.isempty ()) - return octave_value (Array (dim_vector (1, 0))); - - check_colon_operand (base, "lower bound"); - check_colon_operand (limit, "upper bound"); - - typename T::val_type base_val = octave_value_extract (base).value (); - typename T::val_type limit_val = octave_value_extract (limit).value (); - - if (increment.is_double_type ()) - { - double increment_val = increment.double_value (); - - return make_int_range (base_val, increment_val, limit_val); - } - - check_colon_operand (increment, "increment"); - - typename T::val_type increment_val - = octave_value_extract (increment).value (); - - return make_int_range (base_val, increment_val, limit_val); -} - -template ::value, - bool>::type = true> -octave_value -make_float_range (const octave_value& base, const octave_value& increment, - const octave_value& limit, bool is_for_cmd_expr) -{ - if (base.isempty () || increment.isempty () || limit.isempty ()) - return octave_value (Array (dim_vector (1, 0))); - - T base_val = octave_value_extract (base); - T increment_val = octave_value_extract (increment); - T limit_val = octave_value_extract (limit); - - return make_float_range (base_val, increment_val, limit_val, - is_for_cmd_expr); -} - - -octave_value -make_char_range (const octave_value& base, const octave_value& increment, - const octave_value& limit) -{ - octave_value retval; - - bool dq_str = (base.is_dq_string () || increment.is_dq_string () - || limit.is_dq_string ()); - - char type = dq_str ? '"' : '\''; - - if (base.isempty () || increment.isempty () || limit.isempty ()) - retval = octave_value ("", type); - else - { - Matrix mtx_base = base.matrix_value (true); - Matrix mtx_increment = increment.matrix_value (true); - Matrix mtx_limit = limit.matrix_value (true); - - range tmp (mtx_base(0), mtx_increment(0), mtx_limit(0)); - - retval = octave_value (tmp); - } - - return retval.convert_to_str (false, true, type); -} - -octave_value -colon_op (const octave_value& base, const octave_value& increment_arg, - const octave_value& limit, bool is_for_cmd_expr) -{ - if (base.isobject () || increment_arg.isobject () || limit.isobject ()) - { - octave_value_list tmp1; - - if (increment_arg.is_defined ()) - { - tmp1(2) = limit; - tmp1(1) = increment_arg; - tmp1(0) = base; - } - else - { - tmp1(1) = limit; - tmp1(0) = base; - } - - interpreter& interp = __get_interpreter__ (); - - symbol_table& symtab = interp.get_symbol_table (); - - octave_value fcn = symtab.find_function ("colon", tmp1); - - if (fcn.is_defined ()) - { - octave_value_list tmp2 = interp.feval (fcn, tmp1, 1); - - return tmp2(0); - } - } - - octave_value increment - = increment_arg.is_defined () ? increment_arg : octave_value (1.0); - - if (base.numel () > 1 || limit.numel () > 1 || increment.numel () > 1) - warning_with_id ("Octave:colon-nonscalar-argument", - "colon arguments should be scalars"); - - if (base.iscomplex () || limit.iscomplex () || increment.iscomplex ()) - warning_with_id ("Octave:colon-complex-argument", - "imaginary part of complex colon arguments is ignored"); - - // FIXME: is there a better way to do this job, maybe using type traits? - - builtin_type_t type_id = get_colon_op_type (base, increment, limit); - - // For compatibility with Matlab, don't allow the range used in - // a FOR loop expression to be converted to a Matrix. - - // For now, these functions create arrays instead of range for - // all types except double. - - switch (type_id) - { - case btyp_double: - case btyp_complex: - return make_float_range (base, increment, limit, is_for_cmd_expr); - - case btyp_float: - case btyp_float_complex: - return make_float_range (base, increment, limit, is_for_cmd_expr); - - case btyp_int8: - return make_int_range (base, increment, limit); - - case btyp_int16: - return make_int_range (base, increment, limit); - - case btyp_int32: - return make_int_range (base, increment, limit); - - case btyp_int64: - return make_int_range (base, increment, limit); - - case btyp_uint8: - return make_int_range (base, increment, limit); - - case btyp_uint16: - return make_int_range (base, increment, limit); - - case btyp_uint32: - return make_int_range (base, increment, limit); - - case btyp_uint64: - return make_int_range (base, increment, limit); - - case btyp_char: - return make_char_range (base, increment, limit); - - case btyp_unknown: - error ("incompatible types found in range expression"); - - default: - error ("invalid types found in range expression"); - } - - return octave_value (); -} - -OCTAVE_NORETURN static void -err_unary_op_conv (const std::string& on) -{ - error ("type conversion failed for unary operator '%s'", on.c_str ()); -} - -octave_value -unary_op (type_info& ti, octave_value::unary_op op, - const octave_value& v) -{ - octave_value retval; - - int t = v.type_id (); - - if (t == octave_class::static_type_id () - || t == octave_classdef::static_type_id ()) - { - type_info::unary_class_op_fcn f = ti.lookup_unary_class_op (op); - - if (! f) - err_unary_op (octave_value::unary_op_as_string (op), v.class_name ()); - - retval = f (v); - } - else - { - // FIXME: we need to handle overloading operators for built-in - // classes (double, char, int8, etc.) - - type_info::unary_op_fcn f = ti.lookup_unary_op (op, t); - - if (f) - retval = f (v.get_rep ()); - else - { - octave_value tv; - octave_base_value::type_conv_fcn cf - = v.numeric_conversion_function (); - - if (! cf) - err_unary_op (octave_value::unary_op_as_string (op), - v.type_name ()); - - octave_base_value *tmp = cf (v.get_rep ()); - - if (! tmp) - err_unary_op_conv (octave_value::unary_op_as_string (op)); - - tv = octave_value (tmp); - retval = unary_op (op, tv); - } - } - - return retval; -} - -octave_value -unary_op (octave_value::unary_op op, const octave_value& v) -{ - type_info& ti = __get_type_info__ (); - - return unary_op (ti, op, v); -} + { + octave_value retval; + + bool dq_str = (base.is_dq_string () || increment.is_dq_string () + || limit.is_dq_string ()); + + char type = dq_str ? '"' : '\''; + + if (base.isempty () || increment.isempty () || limit.isempty ()) + retval = octave_value ("", type); + else + { + Matrix mtx_base = base.matrix_value (true); + Matrix mtx_increment = increment.matrix_value (true); + Matrix mtx_limit = limit.matrix_value (true); + + range tmp (mtx_base(0), mtx_increment(0), mtx_limit(0)); + + retval = octave_value (tmp); + } + + return retval.convert_to_str (false, true, type); + } + + octave_value + colon_op (const octave_value& base, const octave_value& increment_arg, + const octave_value& limit, bool is_for_cmd_expr) + { + if (base.isobject () || increment_arg.isobject () || limit.isobject ()) + { + octave_value_list tmp1; + + if (increment_arg.is_defined ()) + { + tmp1(2) = limit; + tmp1(1) = increment_arg; + tmp1(0) = base; + } + else + { + tmp1(1) = limit; + tmp1(0) = base; + } + + interpreter& interp = __get_interpreter__ (); + + symbol_table& symtab = interp.get_symbol_table (); + + octave_value fcn = symtab.find_function ("colon", tmp1); + + if (fcn.is_defined ()) + { + octave_value_list tmp2 = interp.feval (fcn, tmp1, 1); + + return tmp2(0); + } + } + + octave_value increment + = increment_arg.is_defined () ? increment_arg : octave_value (1.0); + + if (base.numel () > 1 || limit.numel () > 1 || increment.numel () > 1) + warning_with_id ("Octave:colon-nonscalar-argument", + "colon arguments should be scalars"); + + if (base.iscomplex () || limit.iscomplex () || increment.iscomplex ()) + warning_with_id ("Octave:colon-complex-argument", + "imaginary part of complex colon arguments is ignored"); + + // FIXME: is there a better way to do this job, maybe using type traits? + + builtin_type_t type_id = get_colon_op_type (base, increment, limit); + + // For compatibility with Matlab, don't allow the range used in + // a FOR loop expression to be converted to a Matrix. + + // For now, these functions create arrays instead of range for + // all types except double. + + switch (type_id) + { + case btyp_double: + case btyp_complex: + return make_float_range (base, increment, limit, is_for_cmd_expr); + + case btyp_float: + case btyp_float_complex: + return make_float_range (base, increment, limit, is_for_cmd_expr); + + case btyp_int8: + return make_int_range (base, increment, limit); + + case btyp_int16: + return make_int_range (base, increment, limit); + + case btyp_int32: + return make_int_range (base, increment, limit); + + case btyp_int64: + return make_int_range (base, increment, limit); + + case btyp_uint8: + return make_int_range (base, increment, limit); + + case btyp_uint16: + return make_int_range (base, increment, limit); + + case btyp_uint32: + return make_int_range (base, increment, limit); + + case btyp_uint64: + return make_int_range (base, increment, limit); + + case btyp_char: + return make_char_range (base, increment, limit); + + case btyp_unknown: + error ("incompatible types found in range expression"); + + default: + error ("invalid types found in range expression"); + } + + return octave_value (); + } + + OCTAVE_NORETURN static void + err_unary_op_conv (const std::string& on) + { + error ("type conversion failed for unary operator '%s'", on.c_str ()); + } + + octave_value + unary_op (type_info& ti, octave_value::unary_op op, + const octave_value& v) + { + octave_value retval; + + int t = v.type_id (); + + if (t == octave_class::static_type_id () + || t == octave_classdef::static_type_id ()) + { + type_info::unary_class_op_fcn f = ti.lookup_unary_class_op (op); + + if (! f) + err_unary_op (octave_value::unary_op_as_string (op), v.class_name ()); + + retval = f (v); + } + else + { + // FIXME: we need to handle overloading operators for built-in + // classes (double, char, int8, etc.) + + type_info::unary_op_fcn f = ti.lookup_unary_op (op, t); + + if (f) + retval = f (v.get_rep ()); + else + { + octave_value tv; + octave_base_value::type_conv_fcn cf + = v.numeric_conversion_function (); + + if (! cf) + err_unary_op (octave_value::unary_op_as_string (op), + v.type_name ()); + + octave_base_value *tmp = cf (v.get_rep ()); + + if (! tmp) + err_unary_op_conv (octave_value::unary_op_as_string (op)); + + tv = octave_value (tmp); + retval = unary_op (op, tv); + } + } + + return retval; + } + + octave_value + unary_op (octave_value::unary_op op, const octave_value& v) + { + type_info& ti = __get_type_info__ (); + + return unary_op (ti, op, v); + } OCTAVE_END_NAMESPACE(octave) @@ -3748,8 +3714,7 @@ std::string& type_string, std::list& idx) { - const octave_map m = - arg.xmap_value ("%s: second argument must be a structure with fields 'type' and 'subs'", name); + const octave_map m = arg.xmap_value ("%s: second argument must be a structure with fields 'type' and 'subs'", name); if (m.nfields () != 2 || ! m.contains ("type") || ! m.contains ("subs")) error ("%s: second argument must be a structure with fields 'type' and 'subs'", diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/octave-value/ov.h --- a/libinterp/octave-value/ov.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/octave-value/ov.h Fri Dec 02 10:12:40 2022 -0500 @@ -36,7 +36,6 @@ #include #include -#include "Range.h" #include "data-conv.h" #include "idx-vector.h" #include "mach-info.h" @@ -288,34 +287,6 @@ OCTINTERP_API octave_value (const Array& cellstr); OCTINTERP_API octave_value (const octave::idx_vector& idx, bool lazy = true); -private: - - // Remove when public constructors that use this function are removed. - static OCTINTERP_API octave_base_value * - make_range_rep_deprecated (double base, double inc, double limit); - - // Remove when public constructors that use this function are removed. - static OCTINTERP_API octave_base_value * - make_range_rep_deprecated (const Range& r, bool force_range); - -public: - -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - OCTAVE_DEPRECATED (7, "use 'octave_value (range&)' instead") - octave_value (double base, double limit, double inc) - : m_rep (make_range_rep_deprecated (base, inc, limit)) - { - maybe_mutate (); - } - - OCTAVE_DEPRECATED (7, "use 'octave_value (range&)' instead") - octave_value (const Range& r, bool force_range = false) - : m_rep (make_range_rep_deprecated (r, force_range)) - { - maybe_mutate (); - } -#endif - OCTINTERP_API octave_value (const octave::range& r, bool force_range = false); @@ -552,15 +523,6 @@ return m_rep->do_index_op (idx, resize_ok); } -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - OCTAVE_DEPRECATED (7, "use 'octave_value::index_op' instead") - octave_value do_index_op (const octave_value_list& idx, - bool resize_ok = false) - { - return index_op (idx, resize_ok); - } -#endif - OCTINTERP_API octave_value subsasgn (const std::string& type, const std::list& idx, const octave_value& rhs); @@ -1459,27 +1421,10 @@ OCTINTERP_API octave_value& non_const_unary_op (unary_op op); -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - OCTAVE_DEPRECATED (7, "use 'octave_value::non_const_unary_op' instead") - octave_value& do_non_const_unary_op (unary_op op) - { - return non_const_unary_op (op); - } -#endif - OCTINTERP_API octave_value& non_const_unary_op (unary_op op, const std::string& type, const std::list& idx); -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - OCTAVE_DEPRECATED (7, "use 'octave_value::non_const_unary_op' instead") - octave_value& do_non_const_unary_op (unary_op op, const std::string& type, - const std::list& idx) - { - return non_const_unary_op (op, type, idx); - } -#endif - const octave_base_value& get_rep (void) const { return *m_rep; } bool is_copy_of (const octave_value& val) const { return m_rep == val.m_rep; } @@ -1736,87 +1681,6 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) -OCTAVE_DEPRECATED (7, "use 'octave::unary_op' instead") -inline octave_value -do_unary_op (octave::type_info& ti, octave_value::unary_op op, - const octave_value& a) -{ - return octave::unary_op (ti, op, a); -} - -OCTAVE_DEPRECATED (7, "use 'octave::unary_op' instead") -inline octave_value -do_unary_op (octave_value::unary_op op, const octave_value& a) -{ - return octave::unary_op (op, a); -} - -OCTAVE_DEPRECATED (7, "use 'octave::binary_op' instead") -inline octave_value -do_binary_op (octave::type_info& ti, octave_value::binary_op op, - const octave_value& a, const octave_value& b) -{ - return octave::binary_op (ti, op, a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::binary_op' instead") -inline octave_value -do_binary_op (octave::type_info& ti, octave_value::compound_binary_op op, - const octave_value& a, const octave_value& b) -{ - return octave::binary_op (ti, op, a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::binary_op' instead") -inline octave_value -do_binary_op (octave_value::binary_op op, const octave_value& a, - const octave_value& b) -{ - return octave::binary_op (op, a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::binary_op' instead") -inline octave_value -do_binary_op (octave_value::compound_binary_op op, const octave_value& a, - const octave_value& b) -{ - return octave::binary_op (op, a, b); -} - -OCTAVE_DEPRECATED (7, "use 'octave::cat_op' instead") -inline octave_value -do_cat_op (octave::type_info& ti, const octave_value& a, - const octave_value& b, const Array& ra_idx) -{ - return octave::cat_op (ti, a, b, ra_idx); -} - -OCTAVE_DEPRECATED (7, "use 'octave::cat_op' instead") -inline octave_value -do_cat_op (const octave_value& a, const octave_value& b, - const Array& ra_idx) -{ - return octave::cat_op (a, b, ra_idx); -} - -OCTAVE_DEPRECATED (7, "use 'octave::colon_op' instead") -inline octave_value -do_colon_op (const octave_value& base, const octave_value& increment, - const octave_value& limit, bool is_for_cmd_expr = false) -{ - return octave::colon_op (base, increment, limit, is_for_cmd_expr); -} - -OCTAVE_DEPRECATED (7, "use 'octave::colon_op' instead") -inline octave_value -do_colon_op (const octave_value& base, const octave_value& limit, - bool is_for_cmd_expr = false) -{ - return octave::colon_op (base, limit, is_for_cmd_expr); -} -#endif - #define OV_UNOP_FN(name) \ inline octave_value \ name (const octave_value& a) \ diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/parse-tree/bp-table.h --- a/libinterp/parse-tree/bp-table.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/parse-tree/bp-table.h Fri Dec 02 10:12:40 2022 -0500 @@ -39,217 +39,172 @@ OCTAVE_BEGIN_NAMESPACE(octave) -class tree_evaluator; - -struct bp_type -{ -public: - bp_type (int l, const std::string& c) : line (l), cond (c) { } - - //-------- + class tree_evaluator; - int line; - std::string cond; -}; + struct bp_type + { + public: + bp_type (int l, const std::string& c) : line (l), cond (c) { } -// Interface to breakpoints. -class OCTINTERP_API bp_table -{ -public: + //-------- - bp_table (tree_evaluator& tw) - : m_evaluator (tw), m_bp_set (), m_errors_that_stop (), - m_caught_that_stop (), m_warnings_that_stop () - { } - - ~bp_table (void) = default; - - // Set of breakpoint lines. - typedef std::set bp_lines; + int line; + std::string cond; + }; - typedef bp_lines::const_iterator const_bp_lines_iterator; - typedef bp_lines::iterator bp_lines_iterator; - - typedef std::map fname_line_map; - - typedef fname_line_map::const_iterator const_fname_line_map_iterator; - typedef fname_line_map::iterator fname_line_map_iterator; - - typedef std::map > fname_bp_map; - typedef fname_bp_map::const_iterator const_fname_bp_map_iterator; - typedef fname_bp_map::iterator fname_bp_map_iterator; + // Interface to breakpoints. + class OCTINTERP_API bp_table + { + public: -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - OCTAVE_DEPRECATED (7, "use 'bp_table::add_breakpoints_in_function' instead") - int add_breakpoint (const std::string& fname = "", - const std::string& class_name = "", - int line = 1, - const std::string& condition = "") - { - return add_breakpoint_in_function (fname, class_name, line, condition); - } + bp_table (tree_evaluator& tw) + : m_evaluator (tw), m_bp_set (), m_errors_that_stop (), + m_caught_that_stop (), m_warnings_that_stop () + { } - OCTAVE_DEPRECATED (7, "use 'bp_table::add_breakpoints_in_function' instead") - bp_lines add_breakpoint (const std::string& fname = "", - const std::string& class_name = "", - const bp_lines& lines = bp_lines (), - const std::string& condition = "") - { - return add_breakpoints_in_function (fname, class_name, lines, condition); - } -#endif + ~bp_table (void) = default; + + // Set of breakpoint lines. + typedef std::set bp_lines; + + typedef bp_lines::const_iterator const_bp_lines_iterator; + typedef bp_lines::iterator bp_lines_iterator; - // Add a breakpoint at the nearest executable line in a function. - int add_breakpoint_in_function (const std::string& fname = "", - const std::string& class_name = "", - int line = 1, - const std::string& condition = ""); + typedef std::map fname_line_map; + + typedef fname_line_map::const_iterator const_fname_line_map_iterator; + typedef fname_line_map::iterator fname_line_map_iterator; - // Add a set of breakpoints at the nearest executable lines in a - // function. - bp_lines add_breakpoints_in_function (const std::string& fname = "", - const std::string& class_name = "", - const bp_lines& lines = bp_lines (), - const std::string& condition = ""); + typedef std::map > fname_bp_map; + typedef fname_bp_map::const_iterator const_fname_bp_map_iterator; + typedef fname_bp_map::iterator fname_bp_map_iterator; - // Add a breakpoint at the nearest executable line in a file. - int add_breakpoint_in_file (const std::string& file = "", - int line = 1, - const std::string& condition = ""); - - // Add a set of breakpoints at the nearest executable lines in a - // file. - bp_lines add_breakpoints_in_file (const std::string& file = "", - const bp_lines& lines = bp_lines (), + // Add a breakpoint at the nearest executable line in a function. + int add_breakpoint_in_function (const std::string& fname = "", + const std::string& class_name = "", + int line = 1, const std::string& condition = ""); -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - OCTAVE_DEPRECATED (7, "use 'bp_table::remove_breakpoint_from_function' instead") - int remove_breakpoint (const std::string& fname = "", - int line = 1) - { - return remove_breakpoint_from_function (fname, line); - } + // Add a set of breakpoints at the nearest executable lines in a + // function. + bp_lines add_breakpoints_in_function (const std::string& fname = "", + const std::string& class_name = "", + const bp_lines& lines = bp_lines (), + const std::string& condition = ""); - OCTAVE_DEPRECATED (7, "use 'bp_table::remove_breakpoints_from_function' instead") - int remove_breakpoint (const std::string& fname = "", - const bp_lines& lines = bp_lines ()) - { - return remove_breakpoints_from_function (fname, lines); - } -#endif + // Add a breakpoint at the nearest executable line in a file. + int add_breakpoint_in_file (const std::string& file = "", + int line = 1, + const std::string& condition = ""); + + // Add a set of breakpoints at the nearest executable lines in a + // file. + bp_lines add_breakpoints_in_file (const std::string& file = "", + const bp_lines& lines = bp_lines (), + const std::string& condition = ""); - // Remove a breakpoint from the given line in file. - int remove_breakpoint_from_function (const std::string& fname = "", - int line = 1); + // Remove a breakpoint from the given line in file. + int remove_breakpoint_from_function (const std::string& fname = "", + int line = 1); - // Remove a set of breakpoints from the given lines in file. - int remove_breakpoints_from_function (const std::string& fname = "", - const bp_lines& lines = bp_lines ()); + // Remove a set of breakpoints from the given lines in file. + int remove_breakpoints_from_function (const std::string& fname = "", + const bp_lines& lines = bp_lines ()); - // Remove all the breakpoints in a specified function. - bp_lines remove_all_breakpoints_from_function (const std::string& fname, - bool silent = false); + // Remove all the breakpoints in a specified function. + bp_lines remove_all_breakpoints_from_function (const std::string& fname, + bool silent = false); - // Remove a breakpoint from the given line in file. - int remove_breakpoint_from_file (const std::string& file = "", - int line = 1); + // Remove a breakpoint from the given line in file. + int remove_breakpoint_from_file (const std::string& file = "", + int line = 1); - // Remove a set of breakpoints from the given lines in file. - int remove_breakpoints_from_file (const std::string& file = "", - const bp_lines& lines = bp_lines ()); + // Remove a set of breakpoints from the given lines in file. + int remove_breakpoints_from_file (const std::string& file = "", + const bp_lines& lines = bp_lines ()); -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - OCTAVE_DEPRECATED (7, "use 'bp_table::remove_all_breakpoints_from_function' instead") - bp_lines remove_all_breakpoints_in_file (const std::string& fname, - bool silent = false) - { - return remove_all_breakpoints_from_function (fname, silent); - } -#endif + // Remove all the breakpoints from a file. + bp_lines remove_all_breakpoints_from_file (const std::string& file, + bool silent = false); + + // Remove all the breakpoints registered with octave. + void remove_all_breakpoints (void); - // Remove all the breakpoints from a file. - bp_lines remove_all_breakpoints_from_file (const std::string& file, - bool silent = false); + // Return all breakpoints. Each element of the map is a vector + // containing the breakpoints corresponding to a given function name. + fname_bp_map get_breakpoint_list (const octave_value_list& fname_list); + + bool have_breakpoints (void) { return (! m_bp_set.empty ()); } - // Remove all the breakpoints registered with octave. - void remove_all_breakpoints (void); - - // Return all breakpoints. Each element of the map is a vector - // containing the breakpoints corresponding to a given function name. - fname_bp_map get_breakpoint_list (const octave_value_list& fname_list); - - bool have_breakpoints (void) { return (! m_bp_set.empty ()); } + // Should we enter debugging for this particular error identifier? + bool debug_on_err (const std::string& id) + { + return (m_errors_that_stop.empty () || m_errors_that_stop.count (id)); + } - // Should we enter debugging for this particular error identifier? - bool debug_on_err (const std::string& id) - { - return (m_errors_that_stop.empty () || m_errors_that_stop.count (id)); - } + // Should we enter debugging for this particular identifier in a try/catch? + bool debug_on_caught (const std::string& id) + { + return (m_caught_that_stop.empty () || m_caught_that_stop.count (id)); + } - // Should we enter debugging for this particular identifier in a try/catch? - bool debug_on_caught (const std::string& id) - { - return (m_caught_that_stop.empty () || m_caught_that_stop.count (id)); - } + // Should we enter debugging for this particular warning identifier? + bool debug_on_warn (const std::string& id) + { + return (m_warnings_that_stop.empty () || m_warnings_that_stop.count (id)); + } - // Should we enter debugging for this particular warning identifier? - bool debug_on_warn (const std::string& id) - { - return (m_warnings_that_stop.empty () || m_warnings_that_stop.count (id)); - } + octave_map stop_on_err_warn_status (bool to_screen); + + void dbstop_process_map_args (const octave_map& mv); - octave_map stop_on_err_warn_status (bool to_screen); + void dbclear_all_signals (void); - void dbstop_process_map_args (const octave_map& mv); + bool condition_valid (const std::string& cond); - void dbclear_all_signals (void); - - bool condition_valid (const std::string& cond); + void parse_dbfunction_params (const char *who, + const octave_value_list& args, + std::string& fcn_name, + std::string& class_name, + bp_table::bp_lines& lines, + std::string& cond); - void parse_dbfunction_params (const char *who, - const octave_value_list& args, - std::string& fcn_name, - std::string& class_name, - bp_table::bp_lines& lines, - std::string& cond); + private: + + typedef std::set::const_iterator const_bp_set_iterator; + typedef std::set::iterator bp_set_iterator; -private: - - typedef std::set::const_iterator const_bp_set_iterator; - typedef std::set::iterator bp_set_iterator; + tree_evaluator& m_evaluator; - tree_evaluator& m_evaluator; - - // Set of function (.m file) names containing at least one breakpoint. - std::set m_bp_set; + // Set of function (.m file) names containing at least one breakpoint. + std::set m_bp_set; - // Set of error and warning message IDs that cause us to stop - // *if* Vdebug_on_error / Vdebug_on_caught / Vdebug_on_warning is set. - // Empty means stop on any error / caught error / warning. - std::set m_errors_that_stop; - std::set m_caught_that_stop; - std::set m_warnings_that_stop; + // Set of error and warning message IDs that cause us to stop + // *if* Vdebug_on_error / Vdebug_on_caught / Vdebug_on_warning is set. + // Empty means stop on any error / caught error / warning. + std::set m_errors_that_stop; + std::set m_caught_that_stop; + std::set m_warnings_that_stop; - void set_stop_flag (const char *who, const std::string& condition, - bool on_off); + void set_stop_flag (const char *who, const std::string& condition, + bool on_off); - void process_id_list (const char *who, const std::string& condition, - const octave_value_list& args, - int nargin, int& pos, bool on_off, - std::set& id_list); + void process_id_list (const char *who, const std::string& condition, + const octave_value_list& args, + int nargin, int& pos, bool on_off, + std::set& id_list); - bool add_breakpoint_1 (octave_user_code *fcn, const std::string& fname, - const bp_lines& line, const std::string& condition, - bp_lines& retval); + bool add_breakpoint_1 (octave_user_code *fcn, const std::string& fname, + const bp_lines& line, const std::string& condition, + bp_lines& retval); - int remove_breakpoint_1 (octave_user_code *fcn, const std::string&, - const bp_lines& lines); + int remove_breakpoint_1 (octave_user_code *fcn, const std::string&, + const bp_lines& lines); - bp_lines remove_all_breakpoints_in_file_1 (octave_user_code *fcn, - const std::string& fname); -}; + bp_lines remove_all_breakpoints_in_file_1 (octave_user_code *fcn, + const std::string& fname); + }; OCTAVE_END_NAMESPACE(octave) diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/parse-tree/lex.h --- a/libinterp/parse-tree/lex.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/parse-tree/lex.h Fri Dec 02 10:12:40 2022 -0500 @@ -691,10 +691,6 @@ void warn_deprecated_syntax (const std::string& msg); - void warn_deprecated_operator (const std::string& deprecated_op, - const std::string& recommended_op, - const std::string& version); - void push_token (token *); token * current_token (void); diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/parse-tree/lex.ll --- a/libinterp/parse-tree/lex.ll Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/parse-tree/lex.ll Fri Dec 02 10:12:40 2022 -0500 @@ -183,28 +183,6 @@ } \ while (0) -#define CMD_OR_DEPRECATED_OP(PATTERN, REPLACEMENT, VERSION, TOK) \ - do \ - { \ - curr_lexer->lexer_debug (PATTERN); \ - \ - if (curr_lexer->looks_like_command_arg ()) \ - { \ - yyless (0); \ - curr_lexer->push_start_state (COMMAND_START); \ - } \ - else \ - { \ - curr_lexer->warn_deprecated_operator (PATTERN, REPLACEMENT, \ - #VERSION); \ - /* set COMPAT to true here to avoid warning about \ - compatibility since we've already warned about the \ - operator being deprecated. */ \ - return curr_lexer->handle_op (TOK, false, true); \ - } \ - } \ - while (0) - #define CMD_OR_UNARY_OP(PATTERN, TOK, COMPAT) \ do \ { \ @@ -1088,28 +1066,6 @@ curr_lexer->m_string_text += '\v'; } -(\.\.\.){S}*{NL} { - curr_lexer->lexer_debug ("(\\.\\.\\.){S}*{NL}"); - - /* FIXME: Remove support for '...' continuation in Octave 9 */ - static const char *msg = "'...' continuations in double-quoted character strings were deprecated in version 7 and will not be allowed in a future version of Octave; please use '\\' instead"; - - curr_lexer->warn_deprecated_syntax (msg); - - HANDLE_STRING_CONTINUATION; - } - -\\{S}+{NL} { - curr_lexer->lexer_debug ("\\\\{S}+{NL}"); - - /* FIXME: Remove support for WS after line continuation in Octave 9 */ - static const char *msg = "whitespace after continuation markers in double-quoted character strings were deprecated in version 7 and will not be allowed in a future version of Octave"; - - curr_lexer->warn_deprecated_syntax (msg); - - HANDLE_STRING_CONTINUATION; - } - \\{NL} { curr_lexer->lexer_debug ("\\\\{NL}"); @@ -1302,17 +1258,6 @@ // Deprecated C preprocessor style continuation markers. %} -\\{S}*{NL} | -\\{S}*{CCHAR}{ANY_EXCEPT_NL}*{NL} { - curr_lexer->lexer_debug ("\\\\{S}*{NL}|\\\\{S}*{CCHAR}{ANY_EXCEPT_NL}*{NL}"); - - /* FIXME: Remove support for '\\' line continuation in Octave 9 */ - static const char *msg = "using continuation marker \\ outside of double quoted strings was deprecated in version 7 and will be removed from a future version of Octave, use ... instead"; - - curr_lexer->warn_deprecated_syntax (msg); - - curr_lexer->handle_continuation (); - } %{ // End of file. @@ -1644,13 +1589,10 @@ %} ":" { CMD_OR_OP (":", ':', true); } -".+" { CMD_OR_DEPRECATED_OP (".+", "+", 7, '+'); } -".-" { CMD_OR_DEPRECATED_OP (".-", "-", 7, '-'); } ".*" { CMD_OR_OP (".*", EMUL, true); } "./" { CMD_OR_OP ("./", EDIV, true); } ".\\" { CMD_OR_OP (".\\", ELEFTDIV, true); } ".^" { CMD_OR_OP (".^", EPOW, true); } -".**" { CMD_OR_DEPRECATED_OP (".**", ".^", 7, EPOW); } "<=" { CMD_OR_OP ("<=", EXPR_LE, true); } "==" { CMD_OR_OP ("==", EXPR_EQ, true); } "!=" { CMD_OR_OP ("!=", EXPR_NE, false); } @@ -1680,7 +1622,6 @@ } "^" { CMD_OR_OP ("^", POW, true); } -"**" { CMD_OR_DEPRECATED_OP ("**", "^", 7, POW); } "&&" { CMD_OR_OP ("&&", EXPR_AND_AND, true); } "||" { CMD_OR_OP ("||", EXPR_OR_OR, true); } @@ -1817,15 +1758,11 @@ "*=" { CMD_OR_OP ("*=", MUL_EQ, false); } "/=" { CMD_OR_OP ("/=", DIV_EQ, false); } "\\=" { CMD_OR_OP ("\\=", LEFTDIV_EQ, false); } -".+=" { CMD_OR_DEPRECATED_OP (".+=", "+=", 7, ADD_EQ); } -".-=" { CMD_OR_DEPRECATED_OP (".-=", "-=", 7, SUB_EQ); } ".*=" { CMD_OR_OP (".*=", EMUL_EQ, false); } "./=" { CMD_OR_OP ("./=", EDIV_EQ, false); } ".\\=" { CMD_OR_OP (".\\=", ELEFTDIV_EQ, false); } "^=" { CMD_OR_OP ("^=", POW_EQ, false); } -"**=" { CMD_OR_DEPRECATED_OP ("**=", "^=", 7, POW_EQ); } ".^=" { CMD_OR_OP (".^=", EPOW_EQ, false); } -".**=" { CMD_OR_DEPRECATED_OP (".**=", ".^=", 7, EPOW_EQ); } "&=" { CMD_OR_OP ("&=", AND_EQ, false); } "|=" { CMD_OR_OP ("|=", OR_EQ, false); } @@ -3667,16 +3604,6 @@ } void - base_lexer::warn_deprecated_operator (const std::string& deprecated_op, - const std::string& recommended_op, - const std::string& version) - { - std::string msg = "the '" + deprecated_op + "' operator was deprecated in version " + version + " and will not be allowed in a future version of Octave; please use '" + recommended_op + "' instead"; - - warn_deprecated_syntax (msg); - } - - void base_lexer::push_token (token *tok) { YYSTYPE *lval = yyget_lval (m_scanner); diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/parse-tree/oct-lvalue.h --- a/libinterp/parse-tree/oct-lvalue.h Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/parse-tree/oct-lvalue.h Fri Dec 02 10:12:40 2022 -0500 @@ -81,14 +81,6 @@ void unary_op (octave_value::unary_op op); -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - OCTAVE_DEPRECATED (7, "use 'octave_lvalue::unary_op' instead") - void do_unary_op (octave_value::unary_op op) - { - return unary_op (op); - } -#endif - octave_value value (void) const; private: diff -r c2a0e546aab1 -r 3b7852a822e8 libinterp/parse-tree/pt-eval.cc --- a/libinterp/parse-tree/pt-eval.cc Fri Dec 02 10:11:46 2022 -0500 +++ b/libinterp/parse-tree/pt-eval.cc Fri Dec 02 10:12:40 2022 -0500 @@ -75,616 +75,855 @@ OCTAVE_BEGIN_NAMESPACE(octave) -// Normal evaluator. - -class quit_debug_exception -{ -public: - - quit_debug_exception (bool all = false) : m_all (all) { } - - quit_debug_exception (const quit_debug_exception&) = default; - - quit_debug_exception& operator = (const quit_debug_exception&) = default; - - ~quit_debug_exception (void) = default; - - bool all (void) const { return m_all; } - -private: - - bool m_all; -}; - -class debugger -{ -public: - - enum execution_mode - { - EX_NORMAL = 0, - EX_CONTINUE = 1, - EX_QUIT = 2, - EX_QUIT_ALL = 3 + // Normal evaluator. + + class quit_debug_exception + { + public: + + quit_debug_exception (bool all = false) : m_all (all) { } + + quit_debug_exception (const quit_debug_exception&) = default; + + quit_debug_exception& operator = (const quit_debug_exception&) = default; + + ~quit_debug_exception (void) = default; + + bool all (void) const { return m_all; } + + private: + + bool m_all; }; - debugger (interpreter& interp, std::size_t level) - : m_interpreter (interp), m_level (level), - m_execution_mode (EX_NORMAL), m_in_debug_repl (false) - { } - - int server_loop (void); - - void repl (const std::string& prompt = "debug> "); - - bool in_debug_repl (void) const { return m_in_debug_repl; } - - void dbcont (void) { m_execution_mode = EX_CONTINUE; } - - void dbquit (bool all = false) - { - if (all) - m_execution_mode = EX_QUIT_ALL; - else - m_execution_mode = EX_QUIT; - } - - bool quitting_debugger (void) const; - -private: - - interpreter& m_interpreter; - - std::size_t m_level; - execution_mode m_execution_mode; - bool m_in_debug_repl; -}; - -// FIXME: Could the debugger server_loop and repl functions be merged -// with the corresponding tree_evaluator functions or do they need to -// remain separate? They perform nearly the same functions. - -int debugger::server_loop (void) -{ - // Process events from the event queue. - - tree_evaluator& tw = m_interpreter.get_evaluator (); - - void (tree_evaluator::*server_mode_fptr) (bool) - = &tree_evaluator::server_mode; - unwind_action act (server_mode_fptr, &tw, true); - - int exit_status = 0; - - do - { - if (m_execution_mode == EX_CONTINUE || tw.dbstep_flag ()) - break; - - if (quitting_debugger ()) - break; - - try - { - // FIXME: Should we call octave_quit in the octave::sleep - // and/or command_editor::run_event_hooks functions? - - octave_quit (); - - // FIXME: Running the event queue should be decoupled from - // the command_editor. - - // FIXME: Is it OK to use command_editor::run_event_hooks - // here? It may run more than one queued function per call, - // and it seems that the checks at the top of the loop - // probably need to be done after each individual event - // function is executed. For now, maybe the simplest thing - // would be to pass a predicate function (lambda expression) - // to the command_editor::run_event_hooks and have it check - // that and break out of the eval loop(s) if the condition - // is met? - - // FIXME: We should also use a condition variable to manage - // the execution of entries in the queue and eliminate the - // need for the busy-wait loop. - - command_editor::run_event_hooks (); - - release_unreferenced_dynamic_libraries (); - - sleep (0.1); - } - catch (const interrupt_exception&) - { - octave_interrupt_state = 1; - m_interpreter.recover_from_exception (); - - // Required newline when the user does Ctrl+C at the prompt. - if (m_interpreter.interactive ()) - octave_stdout << "\n"; - } - catch (const index_exception& e) - { - m_interpreter.recover_from_exception (); - - std::cerr << "error: unhandled index exception: " - << e.message () << " -- trying to return to prompt" - << std::endl; - } - catch (const execution_exception& ee) - { - error_system& es = m_interpreter.get_error_system (); - - es.save_exception (ee); - es.display_exception (ee); - - if (m_interpreter.interactive ()) - { - m_interpreter.recover_from_exception (); - } - else - { - // We should exit with a nonzero status. - exit_status = 1; - break; - } - } - catch (const quit_debug_exception& qde) - { - if (qde.all ()) - throw; - - // Continue in this debug level. - } - catch (const std::bad_alloc&) - { - m_interpreter.recover_from_exception (); - - std::cerr << "error: out of memory -- trying to return to prompt" - << std::endl; - } - } - while (exit_status == 0); - - if (exit_status == EOF) - { - if (m_interpreter.interactive ()) - octave_stdout << "\n"; - - exit_status = 0; - } - - return exit_status; -} - -void debugger::repl (const std::string& prompt_arg) -{ - unwind_protect frame; - - frame.protect_var (m_in_debug_repl); - frame.protect_var (m_execution_mode); - - m_in_debug_repl = true; - - tree_evaluator& tw = m_interpreter.get_evaluator (); - - bool silent = tw.quiet_breakpoint_flag (false); - - frame.add (&tree_evaluator::restore_frame, &tw, - tw.current_call_stack_frame_number ()); - - tw.goto_frame (tw.debug_frame ()); - - octave_user_code *caller = tw.current_user_code (); - std::string fcn_file_nm, fcn_nm; - - if (caller) - { - fcn_file_nm = caller->fcn_file_name (); - fcn_nm = fcn_file_nm.empty () ? caller->name () : fcn_file_nm; - } - - int curr_debug_line = tw.current_line (); - - std::ostringstream buf; - - input_system& input_sys = m_interpreter.get_input_system (); - - event_manager& evmgr = m_interpreter.get_event_manager (); - - if (! fcn_nm.empty ()) - { - if (input_sys.gud_mode ()) - { - static char ctrl_z = 'Z' & 0x1f; - - buf << ctrl_z << ctrl_z << fcn_nm << ':' << curr_debug_line; - } - else - { - // FIXME: we should come up with a clean way to detect - // that we are stopped on the no-op command that marks the - // end of a function or script. - - if (! silent) - { - std::shared_ptr frm = tw.current_user_frame (); - - frm->display_stopped_in_message (buf); - } - - evmgr.enter_debugger_event (fcn_nm, fcn_file_nm, curr_debug_line); - - evmgr.set_workspace (); - - frame.add (&event_manager::execute_in_debugger_event, &evmgr, - fcn_nm, curr_debug_line); - - if (! silent) - { - std::string line_buf; - - if (caller) - line_buf = caller->get_code_line (curr_debug_line); - - if (! line_buf.empty ()) - buf << curr_debug_line << ": " << line_buf; - } - } - } - - if (silent) - command_editor::erase_empty_line (true); - - std::string stopped_in_msg = buf.str (); - - if (m_interpreter.server_mode ()) - { - if (! stopped_in_msg.empty ()) - octave_stdout << stopped_in_msg << std::endl; - - evmgr.push_event_queue (); - - frame.add (&event_manager::pop_event_queue, &evmgr); - - frame.add (&tree_evaluator::set_parser, &tw, tw.get_parser ()); - - std::shared_ptr - debug_parser (new push_parser (m_interpreter)); - - tw.set_parser (debug_parser); - - server_loop (); - } - else + class debugger + { + public: + + enum execution_mode + { + EX_NORMAL = 0, + EX_CONTINUE = 1, + EX_QUIT = 2, + EX_QUIT_ALL = 3 + }; + + debugger (interpreter& interp, std::size_t level) + : m_interpreter (interp), m_level (level), + m_execution_mode (EX_NORMAL), m_in_debug_repl (false) + { } + + int server_loop (void); + + void repl (const std::string& prompt = "debug> "); + + bool in_debug_repl (void) const { return m_in_debug_repl; } + + void dbcont (void) { m_execution_mode = EX_CONTINUE; } + + void dbquit (bool all = false) { - if (! stopped_in_msg.empty ()) - std::cerr << stopped_in_msg << std::endl; - - std::string tmp_prompt = prompt_arg; - if (m_level > 0) - tmp_prompt = "[" + std::to_string (m_level) + "]" + prompt_arg; - - frame.add (&input_system::set_PS1, &input_sys, input_sys.PS1 ()); - input_sys.PS1 (tmp_prompt); - - if (! m_interpreter.interactive ()) - { - void (interpreter::*interactive_fptr) (bool) - = &interpreter::interactive; - frame.add (interactive_fptr, &m_interpreter, - m_interpreter.interactive ()); - - m_interpreter.interactive (true); - - // FIXME: should debugging be possible in an embedded - // interpreter? - - application *app = application::app (); - - if (app) - { - void (application::*forced_interactive_fptr) (bool) - = &application::forced_interactive; - frame.add (forced_interactive_fptr, app, - app->forced_interactive ()); - - app->forced_interactive (true); - } - } - -#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER) - - input_reader reader (m_interpreter); - - push_parser debug_parser (m_interpreter); - -#else - - parser debug_parser (m_interpreter); - -#endif - - error_system& es = m_interpreter.get_error_system (); - - while (m_in_debug_repl) - { - if (m_execution_mode == EX_CONTINUE || tw.dbstep_flag ()) - break; - - if (quitting_debugger ()) - break; - - try - { - debug_parser.reset (); - -#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER) - - int retval = 0; - - std::string prompt - = command_editor::decode_prompt_string (tmp_prompt); - - do - { - bool eof = false; - std::string input_line = reader.get_input (prompt, eof); - - if (eof) - { - retval = EOF; - break; - } - - retval = debug_parser.run (input_line, false); - - prompt = command_editor::decode_prompt_string (input_sys.PS2 ()); - } - while (retval < 0); - -#else - - int retval = debug_parser.run (); - -#endif - if (command_editor::interrupt (false)) - { - // Break regardless of m_execution_mode value. - - quitting_debugger (); - - break; - } - else - { - if (retval == 0) - { - std::shared_ptr stmt_list - = debug_parser.statement_list (); - - if (stmt_list) - stmt_list->accept (tw); - - if (octave_completion_matches_called) - octave_completion_matches_called = false; - - // FIXME: the following statement is here because - // the last command may have been a dbup, dbdown, or - // dbstep command that changed the current debug - // frame. If so, we need to reset the current frame - // for the call stack. But is this right way to do - // this job? What if the statement list was - // something like "dbup; dbstack"? Will the call to - // dbstack use the right frame? If not, how can we - // fix this problem? - tw.goto_frame (tw.debug_frame ()); - } - - octave_quit (); - } - } - catch (const execution_exception& ee) - { - es.save_exception (ee); - es.display_exception (ee); - - // Ignore errors when in debugging mode; - m_interpreter.recover_from_exception (); - } - catch (const quit_debug_exception& qde) - { - if (qde.all ()) - throw; - - // Continue in this debug level. - } - } - } -} - -bool debugger::quitting_debugger (void) const -{ - if (m_execution_mode == EX_QUIT) - { - // If there is no enclosing debug level or the top-level - // repl is not active, handle dbquit the same as dbcont. - - if (m_level > 0 || m_interpreter.server_mode () - || m_interpreter.in_top_level_repl ()) - throw quit_debug_exception (); + if (all) + m_execution_mode = EX_QUIT_ALL; else - return true; + m_execution_mode = EX_QUIT; } - if (m_execution_mode == EX_QUIT_ALL) - { - // If the top-level repl is not active, handle "dbquit all" - // the same as dbcont. - - if (m_interpreter.server_mode () || m_interpreter.in_top_level_repl ()) - throw quit_debug_exception (true); - else - return true; - } - - return false; -} - -bool tree_evaluator::at_top_level (void) const -{ - return m_call_stack.at_top_level (); -} - -std::string -tree_evaluator::mfilename (const std::string& opt) const -{ - std::string fname; - - octave_user_code *fcn = m_call_stack.current_user_code (); - - if (fcn) - { - fname = fcn->fcn_file_name (); - - if (fname.empty ()) - fname = fcn->name (); - } - - if (opt == "fullpathext") - return fname; - - std::size_t dpos = fname.rfind (sys::file_ops::dir_sep_char ()); - std::size_t epos = fname.rfind ('.'); - - if (epos <= dpos+1) - epos = std::string::npos; - - if (epos != std::string::npos) - fname = fname.substr (0, epos); - - if (opt == "fullpath") - return fname; - - if (dpos != std::string::npos) - fname = fname.substr (dpos+1); - - return fname; -} - -void tree_evaluator::parse_and_execute (const std::string& input, - bool& incomplete_parse) -{ - incomplete_parse = false; - - unwind_protect_var upv (m_in_top_level_repl, true); - - if (at_top_level ()) - { - dbstep_flag (0); - reset_debug_state (); - } - - // FIXME: OK to do this job here, or should it be in the functions - // that do the actual prompting? - - // Update the time stamp for the "prompt" so that automatically - // finding modified files based on file modification times will - // work. In the future, we may do something completely different to - // check for changes to files but for now, we rely on the prompt - // time stamp to limit the checks for file modification times. - - Vlast_prompt_time.stamp (); - - bool eof = false; - - event_manager& evmgr = m_interpreter.get_event_manager (); - - if (command_history::add (input)) - evmgr.append_history (input); - - m_exit_status = m_parser->run (input, eof); - - if (m_exit_status == 0) - { - std::shared_ptr - stmt_list = m_parser->statement_list (); - - if (stmt_list) - { - command_editor::increment_current_command_number (); - - eval (stmt_list, m_interpreter.interactive ()); - - evmgr.set_workspace (); - } - else if (m_parser->at_end_of_input ()) - m_exit_status = EOF; - } - else - incomplete_parse = true; - - // FIXME: Should we be checking m_exit_status or incomplete_parse or - // both here? Could EOF have a value other than -1, and is there - // possible confusion between that state and the parser returning -1? - - if (m_exit_status == -1) - m_exit_status = 0; - else - m_parser->reset (); - - evmgr.pre_input_event (); -} - -void tree_evaluator::get_line_and_eval (void) -{ - std::mutex mtx; - std::unique_lock lock (mtx); - std::condition_variable cv; - bool incomplete_parse = false; - bool evaluation_pending = false; - bool exiting = false; - - input_system& input_sys = m_interpreter.get_input_system (); - event_manager& evmgr = m_interpreter.get_event_manager (); - - while (true) - { - // FIXME: Detect EOF? Use readline? If - // so, then we need to disable idle event loop hook function - // execution. - - std::string ps = incomplete_parse ? input_sys.PS2 () : input_sys.PS1 (); - - std::cout << command_editor::decode_prompt_string (ps); - - std::string input; - std::getline (std::cin, input); - - if (input.empty ()) - continue; - - incomplete_parse = false; - evaluation_pending = true; - exiting = false; - - evmgr.post_event - ([&] (interpreter& interp) + bool quitting_debugger (void) const; + + private: + + interpreter& m_interpreter; + + std::size_t m_level; + execution_mode m_execution_mode; + bool m_in_debug_repl; + }; + + // FIXME: Could the debugger server_loop and repl functions be merged + // with the corresponding tree_evaluator functions or do they need to + // remain separate? They perform nearly the same functions. + + int debugger::server_loop (void) + { + // Process events from the event queue. + + tree_evaluator& tw = m_interpreter.get_evaluator (); + + void (tree_evaluator::*server_mode_fptr) (bool) + = &tree_evaluator::server_mode; + unwind_action act (server_mode_fptr, &tw, true); + + int exit_status = 0; + + do { - // INTERPRETER THREAD - - std::lock_guard local_lock (mtx); + if (m_execution_mode == EX_CONTINUE || tw.dbstep_flag ()) + break; + + if (quitting_debugger ()) + break; try { - interp.parse_and_execute (input, incomplete_parse); + // FIXME: Should we call octave_quit in the octave::sleep + // and/or command_editor::run_event_hooks functions? + + octave_quit (); + + // FIXME: Running the event queue should be decoupled from + // the command_editor. + + // FIXME: Is it OK to use command_editor::run_event_hooks + // here? It may run more than one queued function per call, + // and it seems that the checks at the top of the loop + // probably need to be done after each individual event + // function is executed. For now, maybe the simplest thing + // would be to pass a predicate function (lambda expression) + // to the command_editor::run_event_hooks and have it check + // that and break out of the eval loop(s) if the condition + // is met? + + // FIXME: We should also use a condition variable to manage + // the execution of entries in the queue and eliminate the + // need for the busy-wait loop. + + command_editor::run_event_hooks (); + + release_unreferenced_dynamic_libraries (); + + sleep (0.1); + } + catch (const interrupt_exception&) + { + octave_interrupt_state = 1; + m_interpreter.recover_from_exception (); + + // Required newline when the user does Ctrl+C at the prompt. + if (m_interpreter.interactive ()) + octave_stdout << "\n"; + } + catch (const index_exception& e) + { + m_interpreter.recover_from_exception (); + + std::cerr << "error: unhandled index exception: " + << e.message () << " -- trying to return to prompt" + << std::endl; + } + catch (const execution_exception& ee) + { + error_system& es = m_interpreter.get_error_system (); + + es.save_exception (ee); + es.display_exception (ee); + + if (m_interpreter.interactive ()) + { + m_interpreter.recover_from_exception (); + } + else + { + // We should exit with a nonzero status. + exit_status = 1; + break; + } + } + catch (const quit_debug_exception& qde) + { + if (qde.all ()) + throw; + + // Continue in this debug level. + } + catch (const std::bad_alloc&) + { + m_interpreter.recover_from_exception (); + + std::cerr << "error: out of memory -- trying to return to prompt" + << std::endl; } - catch (const exit_exception&) + } + while (exit_status == 0); + + if (exit_status == EOF) + { + if (m_interpreter.interactive ()) + octave_stdout << "\n"; + + exit_status = 0; + } + + return exit_status; + } + + void debugger::repl (const std::string& prompt_arg) + { + unwind_protect frame; + + frame.protect_var (m_in_debug_repl); + frame.protect_var (m_execution_mode); + + m_in_debug_repl = true; + + tree_evaluator& tw = m_interpreter.get_evaluator (); + + bool silent = tw.quiet_breakpoint_flag (false); + + frame.add (&tree_evaluator::restore_frame, &tw, + tw.current_call_stack_frame_number ()); + + tw.goto_frame (tw.debug_frame ()); + + octave_user_code *caller = tw.current_user_code (); + std::string fcn_file_nm, fcn_nm; + + if (caller) + { + fcn_file_nm = caller->fcn_file_name (); + fcn_nm = fcn_file_nm.empty () ? caller->name () : fcn_file_nm; + } + + int curr_debug_line = tw.current_line (); + + std::ostringstream buf; + + input_system& input_sys = m_interpreter.get_input_system (); + + event_manager& evmgr = m_interpreter.get_event_manager (); + + if (! fcn_nm.empty ()) + { + if (input_sys.gud_mode ()) + { + static char ctrl_z = 'Z' & 0x1f; + + buf << ctrl_z << ctrl_z << fcn_nm << ':' << curr_debug_line; + } + else + { + // FIXME: we should come up with a clean way to detect + // that we are stopped on the no-op command that marks the + // end of a function or script. + + if (! silent) + { + std::shared_ptr frm = tw.current_user_frame (); + + frm->display_stopped_in_message (buf); + } + + evmgr.enter_debugger_event (fcn_nm, fcn_file_nm, curr_debug_line); + + evmgr.set_workspace (); + + frame.add (&event_manager::execute_in_debugger_event, &evmgr, + fcn_nm, curr_debug_line); + + if (! silent) + { + std::string line_buf; + + if (caller) + line_buf = caller->get_code_line (curr_debug_line); + + if (! line_buf.empty ()) + buf << curr_debug_line << ": " << line_buf; + } + } + } + + if (silent) + command_editor::erase_empty_line (true); + + std::string stopped_in_msg = buf.str (); + + if (m_interpreter.server_mode ()) + { + if (! stopped_in_msg.empty ()) + octave_stdout << stopped_in_msg << std::endl; + + evmgr.push_event_queue (); + + frame.add (&event_manager::pop_event_queue, &evmgr); + + frame.add (&tree_evaluator::set_parser, &tw, tw.get_parser ()); + + std::shared_ptr + debug_parser (new push_parser (m_interpreter)); + + tw.set_parser (debug_parser); + + server_loop (); + } + else + { + if (! stopped_in_msg.empty ()) + std::cerr << stopped_in_msg << std::endl; + + std::string tmp_prompt = prompt_arg; + if (m_level > 0) + tmp_prompt = "[" + std::to_string (m_level) + "]" + prompt_arg; + + frame.add (&input_system::set_PS1, &input_sys, input_sys.PS1 ()); + input_sys.PS1 (tmp_prompt); + + if (! m_interpreter.interactive ()) + { + void (interpreter::*interactive_fptr) (bool) + = &interpreter::interactive; + frame.add (interactive_fptr, &m_interpreter, + m_interpreter.interactive ()); + + m_interpreter.interactive (true); + + // FIXME: should debugging be possible in an embedded + // interpreter? + + application *app = application::app (); + + if (app) + { + void (application::*forced_interactive_fptr) (bool) + = &application::forced_interactive; + frame.add (forced_interactive_fptr, app, + app->forced_interactive ()); + + app->forced_interactive (true); + } + } + +#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER) + + input_reader reader (m_interpreter); + + push_parser debug_parser (m_interpreter); + +#else + + parser debug_parser (m_interpreter); + +#endif + + error_system& es = m_interpreter.get_error_system (); + + while (m_in_debug_repl) { - evaluation_pending = false; - exiting = true; - cv.notify_all (); - throw; + if (m_execution_mode == EX_CONTINUE || tw.dbstep_flag ()) + break; + + if (quitting_debugger ()) + break; + + try + { + debug_parser.reset (); + +#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER) + + int retval = 0; + + std::string prompt + = command_editor::decode_prompt_string (tmp_prompt); + + do + { + bool eof = false; + std::string input_line = reader.get_input (prompt, eof); + + if (eof) + { + retval = EOF; + break; + } + + retval = debug_parser.run (input_line, false); + + prompt = command_editor::decode_prompt_string (input_sys.PS2 ()); + } + while (retval < 0); + +#else + + int retval = debug_parser.run (); + +#endif + if (command_editor::interrupt (false)) + { + // Break regardless of m_execution_mode value. + + quitting_debugger (); + + break; + } + else + { + if (retval == 0) + { + std::shared_ptr stmt_list + = debug_parser.statement_list (); + + if (stmt_list) + stmt_list->accept (tw); + + if (octave_completion_matches_called) + octave_completion_matches_called = false; + + // FIXME: the following statement is here because + // the last command may have been a dbup, dbdown, or + // dbstep command that changed the current debug + // frame. If so, we need to reset the current frame + // for the call stack. But is this right way to do + // this job? What if the statement list was + // something like "dbup; dbstack"? Will the call to + // dbstack use the right frame? If not, how can we + // fix this problem? + tw.goto_frame (tw.debug_frame ()); + } + + octave_quit (); + } + } + catch (const execution_exception& ee) + { + es.save_exception (ee); + es.display_exception (ee); + + // Ignore errors when in debugging mode; + m_interpreter.recover_from_exception (); + } + catch (const quit_debug_exception& qde) + { + if (qde.all ()) + throw; + + // Continue in this debug level. + } + } + } + } + + bool debugger::quitting_debugger (void) const + { + if (m_execution_mode == EX_QUIT) + { + // If there is no enclosing debug level or the top-level + // repl is not active, handle dbquit the same as dbcont. + + if (m_level > 0 || m_interpreter.server_mode () + || m_interpreter.in_top_level_repl ()) + throw quit_debug_exception (); + else + return true; + } + + if (m_execution_mode == EX_QUIT_ALL) + { + // If the top-level repl is not active, handle "dbquit all" + // the same as dbcont. + + if (m_interpreter.server_mode () || m_interpreter.in_top_level_repl ()) + throw quit_debug_exception (true); + else + return true; + } + + return false; + } + + bool tree_evaluator::at_top_level (void) const + { + return m_call_stack.at_top_level (); + } + + std::string + tree_evaluator::mfilename (const std::string& opt) const + { + std::string fname; + + octave_user_code *fcn = m_call_stack.current_user_code (); + + if (fcn) + { + fname = fcn->fcn_file_name (); + + if (fname.empty ()) + fname = fcn->name (); + } + + if (opt == "fullpathext") + return fname; + + std::size_t dpos = fname.rfind (sys::file_ops::dir_sep_char ()); + std::size_t epos = fname.rfind ('.'); + + if (epos <= dpos+1) + epos = std::string::npos; + + if (epos != std::string::npos) + fname = fname.substr (0, epos); + + if (opt == "fullpath") + return fname; + + if (dpos != std::string::npos) + fname = fname.substr (dpos+1); + + return fname; + } + + void tree_evaluator::parse_and_execute (const std::string& input, + bool& incomplete_parse) + { + incomplete_parse = false; + + unwind_protect_var upv (m_in_top_level_repl, true); + + if (at_top_level ()) + { + dbstep_flag (0); + reset_debug_state (); + } + + // FIXME: OK to do this job here, or should it be in the functions + // that do the actual prompting? + + // Update the time stamp for the "prompt" so that automatically + // finding modified files based on file modification times will + // work. In the future, we may do something completely different to + // check for changes to files but for now, we rely on the prompt + // time stamp to limit the checks for file modification times. + + Vlast_prompt_time.stamp (); + + bool eof = false; + + event_manager& evmgr = m_interpreter.get_event_manager (); + + if (command_history::add (input)) + evmgr.append_history (input); + + m_exit_status = m_parser->run (input, eof); + + if (m_exit_status == 0) + { + std::shared_ptr + stmt_list = m_parser->statement_list (); + + if (stmt_list) + { + command_editor::increment_current_command_number (); + + eval (stmt_list, m_interpreter.interactive ()); + + evmgr.set_workspace (); + } + else if (m_parser->at_end_of_input ()) + m_exit_status = EOF; + } + else + incomplete_parse = true; + + // FIXME: Should we be checking m_exit_status or incomplete_parse or + // both here? Could EOF have a value other than -1, and is there + // possible confusion between that state and the parser returning -1? + + if (m_exit_status == -1) + m_exit_status = 0; + else + m_parser->reset (); + + evmgr.pre_input_event (); + } + + void tree_evaluator::get_line_and_eval (void) + { + std::mutex mtx; + std::unique_lock lock (mtx); + std::condition_variable cv; + bool incomplete_parse = false; + bool evaluation_pending = false; + bool exiting = false; + + input_system& input_sys = m_interpreter.get_input_system (); + event_manager& evmgr = m_interpreter.get_event_manager (); + + while (true) + { + // FIXME: Detect EOF? Use readline? If + // so, then we need to disable idle event loop hook function + // execution. + + std::string ps = incomplete_parse ? input_sys.PS2 () : input_sys.PS1 (); + + std::cout << command_editor::decode_prompt_string (ps); + + std::string input; + std::getline (std::cin, input); + + if (input.empty ()) + continue; + + incomplete_parse = false; + evaluation_pending = true; + exiting = false; + + evmgr.post_event + ([&] (interpreter& interp) + { + // INTERPRETER THREAD + + std::lock_guard local_lock (mtx); + + try + { + interp.parse_and_execute (input, incomplete_parse); + } + catch (const exit_exception&) + { + evaluation_pending = false; + exiting = true; + cv.notify_all (); + throw; + } + catch (const execution_exception& ee) + { + error_system& es = m_interpreter.get_error_system (); + + es.save_exception (ee); + es.display_exception (ee); + + if (m_interpreter.interactive ()) + { + m_interpreter.recover_from_exception (); + m_parser->reset (); + evaluation_pending = false; + cv.notify_all (); + } + else + { + evaluation_pending = false; + cv.notify_all (); + throw exit_exception (1); + } + } + catch (...) + { + evaluation_pending = false; + cv.notify_all (); + throw; + } + + evaluation_pending = false; + cv.notify_all (); + }); + + // Wait until evaluation is finished before prompting for input + // again. + + cv.wait (lock, [&] { return ! evaluation_pending; }); + + if (exiting) + break; + } + } + + int tree_evaluator::repl (void) + { + // The big loop. Read, Eval, Print, Loop. Normally user + // interaction at the command line in a terminal session, but we may + // also end up here when reading from a pipe or when stdin is + // connected to a file by the magic of input redirection. + + int exit_status = 0; + + // FIXME: should this choice be a command-line option? Note that we + // intend that the push parser interface only be used for + // interactive sessions. + +#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER) + static bool use_command_line_push_parser = true; +#else + static bool use_command_line_push_parser = false; +#endif + + // The following logic is written as it is to allow easy transition + // to setting USE_COMMAND_LINE_PUSH_PARSER at run time and to + // simplify the logic of the main loop below by using the same + // base_parser::run interface for both push and pull parsers. + + std::shared_ptr repl_parser; + + if (m_interpreter.interactive ()) + { + if (use_command_line_push_parser) + { + push_parser *pp + = new push_parser (m_interpreter, + new input_reader (m_interpreter)); + + repl_parser = std::shared_ptr (pp); + } + else + { + parser *pp = new parser (new lexer (m_interpreter)); + repl_parser = std::shared_ptr (pp); + } + } + else + { + parser *pp = new parser (new lexer (stdin, m_interpreter)); + repl_parser = std::shared_ptr (pp); + } + + do + { + try + { + unwind_protect_var upv (m_in_top_level_repl, true); + + repl_parser->reset (); + + if (at_top_level ()) + { + dbstep_flag (0); + reset_debug_state (); + } + + exit_status = repl_parser->run (); + + if (exit_status == 0) + { + std::shared_ptr + stmt_list = repl_parser->statement_list (); + + if (stmt_list) + { + command_editor::increment_current_command_number (); + + eval (stmt_list, m_interpreter.interactive ()); + } + else if (repl_parser->at_end_of_input ()) + { + exit_status = EOF; + break; + } + } + } + catch (const interrupt_exception&) + { + m_interpreter.recover_from_exception (); + + // Required newline when the user does Ctrl+C at the prompt. + if (m_interpreter.interactive ()) + octave_stdout << "\n"; + } + catch (const index_exception& ie) + { + m_interpreter.recover_from_exception (); + + std::cerr << "error: unhandled index exception: " + << ie.message () << " -- trying to return to prompt" + << std::endl; + } + catch (const execution_exception& ee) + { + error_system& es = m_interpreter.get_error_system (); + + es.save_exception (ee); + es.display_exception (ee); + + if (m_interpreter.interactive ()) + m_interpreter.recover_from_exception (); + else + { + // We should exit with a nonzero status. + exit_status = 1; + break; + } + } + catch (const quit_debug_exception&) + { + m_interpreter.recover_from_exception (); + + // FIXME: Does anything else need to happen here? + } + catch (const std::bad_alloc&) + { + m_interpreter.recover_from_exception (); + + std::cerr << "error: out of memory -- trying to return to prompt" + << std::endl; + } + } + while (exit_status == 0); + + if (exit_status == EOF) + { + if (m_interpreter.interactive ()) + octave_stdout << "\n"; + + exit_status = 0; + } + + return exit_status; + } + + int tree_evaluator::server_loop (void) + { + // Process events from the event queue. + + unwind_protect_var upv1 (m_server_mode, true); + + m_exit_status = 0; + + std::shared_ptr parser (new push_parser (m_interpreter)); + unwind_protect_var> upv2 (m_parser, parser); + + // FIXME: We are currently resetting the parser after every call to + // recover_from_exception. This action should probably be handled + // in a more consistent way, but resetting the parser in every call + // to interpreter::recover_from_exception appears to cause + // segfaults in the test suite. + + do + { + try + { + // FIXME: Should we call octave_quit in the octave::sleep + // and/or command_editor::run_event_hooks functions? + + octave_quit (); + + // FIXME: Running the event queue should be decoupled from + // the command_editor. We should also use a condition + // variable to manage the execution of entries in the queue + // and eliminate the need for the busy-wait loop. + + command_editor::run_event_hooks (); + + release_unreferenced_dynamic_libraries (); + + sleep (0.1); + } + catch (const interrupt_exception&) + { + octave_interrupt_state = 1; + m_interpreter.recover_from_exception (); + m_parser->reset (); + + // Required newline when the user does Ctrl+C at the prompt. + if (m_interpreter.interactive ()) + octave_stdout << "\n"; + } + catch (const index_exception& e) + { + m_interpreter.recover_from_exception (); + m_parser->reset (); + + std::cerr << "error: unhandled index exception: " + << e.message () << " -- trying to return to prompt" + << std::endl; } catch (const execution_exception& ee) { @@ -697,1133 +936,874 @@ { m_interpreter.recover_from_exception (); m_parser->reset (); - evaluation_pending = false; - cv.notify_all (); } else { - evaluation_pending = false; - cv.notify_all (); - throw exit_exception (1); + // We should exit with a nonzero status. + m_exit_status = 1; + break; } } - catch (...) + catch (const quit_debug_exception&) { - evaluation_pending = false; - cv.notify_all (); - throw; - } - - evaluation_pending = false; - cv.notify_all (); - }); - - // Wait until evaluation is finished before prompting for input - // again. - - cv.wait (lock, [&] { return ! evaluation_pending; }); - - if (exiting) - break; - } -} - -int tree_evaluator::repl (void) -{ - // The big loop. Read, Eval, Print, Loop. Normally user - // interaction at the command line in a terminal session, but we may - // also end up here when reading from a pipe or when stdin is - // connected to a file by the magic of input redirection. - - int exit_status = 0; - - // FIXME: should this choice be a command-line option? Note that we - // intend that the push parser interface only be used for - // interactive sessions. - -#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER) - static bool use_command_line_push_parser = true; -#else - static bool use_command_line_push_parser = false; -#endif - - // The following logic is written as it is to allow easy transition - // to setting USE_COMMAND_LINE_PUSH_PARSER at run time and to - // simplify the logic of the main loop below by using the same - // base_parser::run interface for both push and pull parsers. - - std::shared_ptr repl_parser; - - if (m_interpreter.interactive ()) - { - if (use_command_line_push_parser) - { - push_parser *pp - = new push_parser (m_interpreter, - new input_reader (m_interpreter)); - - repl_parser = std::shared_ptr (pp); - } - else - { - parser *pp = new parser (new lexer (m_interpreter)); - repl_parser = std::shared_ptr (pp); - } - } - else - { - parser *pp = new parser (new lexer (stdin, m_interpreter)); - repl_parser = std::shared_ptr (pp); - } - - do - { - try - { - unwind_protect_var upv (m_in_top_level_repl, true); - - repl_parser->reset (); - - if (at_top_level ()) - { - dbstep_flag (0); - reset_debug_state (); - } - - exit_status = repl_parser->run (); - - if (exit_status == 0) - { - std::shared_ptr - stmt_list = repl_parser->statement_list (); - - if (stmt_list) - { - command_editor::increment_current_command_number (); - - eval (stmt_list, m_interpreter.interactive ()); - } - else if (repl_parser->at_end_of_input ()) - { - exit_status = EOF; - break; - } - } - } - catch (const interrupt_exception&) - { - m_interpreter.recover_from_exception (); - - // Required newline when the user does Ctrl+C at the prompt. - if (m_interpreter.interactive ()) - octave_stdout << "\n"; - } - catch (const index_exception& ie) - { - m_interpreter.recover_from_exception (); - - std::cerr << "error: unhandled index exception: " - << ie.message () << " -- trying to return to prompt" - << std::endl; - } - catch (const execution_exception& ee) - { - error_system& es = m_interpreter.get_error_system (); - - es.save_exception (ee); - es.display_exception (ee); - - if (m_interpreter.interactive ()) + octave_interrupt_state = 1; m_interpreter.recover_from_exception (); - else - { - // We should exit with a nonzero status. - exit_status = 1; - break; - } - } - catch (const quit_debug_exception&) - { - m_interpreter.recover_from_exception (); - - // FIXME: Does anything else need to happen here? - } - catch (const std::bad_alloc&) - { - m_interpreter.recover_from_exception (); - - std::cerr << "error: out of memory -- trying to return to prompt" - << std::endl; - } - } - while (exit_status == 0); - - if (exit_status == EOF) - { - if (m_interpreter.interactive ()) - octave_stdout << "\n"; - - exit_status = 0; - } - - return exit_status; -} - -int tree_evaluator::server_loop (void) -{ - // Process events from the event queue. - - unwind_protect_var upv1 (m_server_mode, true); - - m_exit_status = 0; - - std::shared_ptr parser (new push_parser (m_interpreter)); - unwind_protect_var> upv2 (m_parser, parser); - - // FIXME: We are currently resetting the parser after every call to - // recover_from_exception. This action should probably be handled - // in a more consistent way, but resetting the parser in every call - // to interpreter::recover_from_exception appears to cause - // segfaults in the test suite. - - do - { - try - { - // FIXME: Should we call octave_quit in the octave::sleep - // and/or command_editor::run_event_hooks functions? - - octave_quit (); - - // FIXME: Running the event queue should be decoupled from - // the command_editor. We should also use a condition - // variable to manage the execution of entries in the queue - // and eliminate the need for the busy-wait loop. - - command_editor::run_event_hooks (); - - release_unreferenced_dynamic_libraries (); - - sleep (0.1); - } - catch (const interrupt_exception&) - { - octave_interrupt_state = 1; - m_interpreter.recover_from_exception (); - m_parser->reset (); - - // Required newline when the user does Ctrl+C at the prompt. - if (m_interpreter.interactive ()) - octave_stdout << "\n"; - } - catch (const index_exception& e) - { - m_interpreter.recover_from_exception (); - m_parser->reset (); - - std::cerr << "error: unhandled index exception: " - << e.message () << " -- trying to return to prompt" - << std::endl; - } - catch (const execution_exception& ee) - { - error_system& es = m_interpreter.get_error_system (); - - es.save_exception (ee); - es.display_exception (ee); - - if (m_interpreter.interactive ()) - { - m_interpreter.recover_from_exception (); - m_parser->reset (); - } - else - { - // We should exit with a nonzero status. - m_exit_status = 1; - break; - } - } - catch (const quit_debug_exception&) - { - octave_interrupt_state = 1; - m_interpreter.recover_from_exception (); - m_parser->reset (); - } - catch (const exit_exception& xe) - { - m_exit_status = xe.exit_status (); - break; - } - catch (const std::bad_alloc&) - { - m_interpreter.recover_from_exception (); - m_parser->reset (); - - std::cerr << "error: out of memory -- trying to return to prompt" - << std::endl; - } - } - while (m_exit_status == 0); - - if (m_exit_status == EOF) - { - if (m_interpreter.interactive ()) - octave_stdout << "\n"; - - m_exit_status = 0; - } - - return m_exit_status; -} - -void tree_evaluator::eval (std::shared_ptr& stmt_list, - bool interactive) -{ - try - { - stmt_list->accept (*this); - - octave_quit (); - - if (! interactive) - { - bool quit = (m_returning || m_breaking); - - if (m_returning) - m_returning = 0; - - if (m_breaking) - m_breaking--; - - if (quit) - return; - } - - if (octave_completion_matches_called) - octave_completion_matches_called = false; - } - catch (const quit_debug_exception&) - { - m_interpreter.recover_from_exception (); - } -} - -octave_value_list -tree_evaluator::eval_string (const std::string& eval_str, bool silent, - int& parse_status, int nargout) -{ - octave_value_list retval; - - parser eval_parser (eval_str, m_interpreter); - - do - { - eval_parser.reset (); - - // If we are looking at - // - // val = eval ("code"); - // - // then don't allow code to be parsed as a command. - - if (nargout > 0) - eval_parser.disallow_command_syntax (); - - parse_status = eval_parser.run (); - - if (parse_status == 0) - { - std::shared_ptr stmt_list - = eval_parser.statement_list (); - - if (stmt_list) - { - tree_statement *stmt = nullptr; - - if (stmt_list->length () == 1 - && (stmt = stmt_list->front ()) - && stmt->is_expression ()) - { - tree_expression *expr = stmt->expression (); - - if (silent) - expr->set_print_flag (false); - - retval = expr->evaluate_n (*this, nargout); - - bool do_bind_ans = false; - - if (expr->is_identifier ()) - do_bind_ans = ! is_variable (expr); - else - do_bind_ans = ! expr->is_assignment_expression (); - - if (do_bind_ans && ! retval.empty ()) - bind_ans (retval(0), expr->print_result ()); - - if (nargout == 0) - retval = octave_value_list (); - } - else if (nargout == 0) - stmt_list->accept (*this); - else - error ("eval: invalid use of statement list"); - - if (returning () || breaking () || continuing ()) - break; - } - else if (eval_parser.at_end_of_input ()) + m_parser->reset (); + } + catch (const exit_exception& xe) + { + m_exit_status = xe.exit_status (); break; - } - } - while (parse_status == 0); - - return retval; -} - -octave_value tree_evaluator::eval_string (const std::string& eval_str, - bool silent, int& parse_status) -{ - octave_value retval; - - octave_value_list tmp = eval_string (eval_str, silent, parse_status, 1); - - if (! tmp.empty ()) - retval = tmp(0); - - return retval; -} - -octave_value_list tree_evaluator::eval_string (const octave_value& arg, - bool silent, int& parse_status, - int nargout) -{ - std::string s = arg.xstring_value ("eval: expecting string argument"); - - return eval_string (s, silent, parse_status, nargout); -} - -octave_value_list tree_evaluator::eval (const std::string& try_code, - int nargout) -{ - int parse_status = 0; - - return eval_string (try_code, nargout > 0, parse_status, nargout); -} - -octave_value_list tree_evaluator::eval (const std::string& try_code, - const std::string& catch_code, - int nargout) -{ - octave_value_list retval; - - error_system& es = m_interpreter.get_error_system (); - - int parse_status = 0; - - bool execution_error = false; - - octave_value_list tmp; - - try - { - tmp = eval_string (try_code, nargout > 0, parse_status, nargout); - } - catch (const execution_exception& ee) - { - es.save_exception (ee); - m_interpreter.recover_from_exception (); - - execution_error = true; - } - - if (parse_status != 0 || execution_error) - { - tmp = eval_string (catch_code, nargout > 0, parse_status, nargout); - - retval = (nargout > 0) ? tmp : octave_value_list (); - } - else - { - if (nargout > 0) - retval = tmp; - - // FIXME: we should really be rethrowing whatever - // exception occurred, not just throwing an - // execution exception. - if (execution_error) - throw execution_exception (); - } - - return retval; -} - -octave_value_list tree_evaluator::evalin (const std::string& context, - const std::string& try_code, - int nargout) -{ - unwind_action act ([=] (std::size_t frm) - { - m_call_stack.restore_frame (frm); - }, m_call_stack.current_frame ()); - - if (context == "caller") - m_call_stack.goto_caller_frame (); - else if (context == "base") - m_call_stack.goto_base_frame (); - else - error (R"(evalin: CONTEXT must be "caller" or "base")"); - - int parse_status = 0; - - return eval_string (try_code, nargout > 0, parse_status, nargout); -} - -octave_value_list tree_evaluator::evalin (const std::string& context, - const std::string& try_code, - const std::string& catch_code, - int nargout) -{ - octave_value_list retval; - - unwind_action act1 ([=] (std::size_t frm) - { - m_call_stack.restore_frame (frm); - }, m_call_stack.current_frame ()); - - if (context == "caller") - m_call_stack.goto_caller_frame (); - else if (context == "base") - m_call_stack.goto_base_frame (); - else - error (R"(evalin: CONTEXT must be "caller" or "base")"); - - error_system& es = m_interpreter.get_error_system (); - - int parse_status = 0; - - bool execution_error = false; - - octave_value_list tmp; - - try - { - tmp = eval_string (try_code, nargout > 0, parse_status, nargout); - } - catch (const execution_exception& ee) - { - es.save_exception (ee); - m_interpreter.recover_from_exception (); - - execution_error = true; - } - - if (parse_status != 0 || execution_error) - { - tmp = eval_string (catch_code, nargout > 0, parse_status, nargout); - - retval = (nargout > 0) ? tmp : octave_value_list (); - } - else - { - if (nargout > 0) - retval = tmp; - - // FIXME: we should really be rethrowing whatever - // exception occurred, not just throwing an - // execution exception. - if (execution_error) - throw execution_exception (); - } - - return retval; -} - -void -tree_evaluator::visit_anon_fcn_handle (tree_anon_fcn_handle&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_argument_list (tree_argument_list&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_arguments_block (tree_arguments_block&) -{ - warning ("function arguments validation blocks are not supported; INCORRECT RESULTS ARE POSSIBLE"); -} - -void -tree_evaluator::visit_args_block_attribute_list (tree_args_block_attribute_list&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_args_block_validation_list (tree_args_block_validation_list&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_arg_validation (tree_arg_validation&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_arg_size_spec (tree_arg_size_spec&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_arg_validation_fcns (tree_arg_validation_fcns&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_binary_expression (tree_binary_expression&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_boolean_expression (tree_boolean_expression&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_compound_binary_expression (tree_compound_binary_expression&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_break_command (tree_break_command& cmd) -{ - if (m_echo_state) - { - int line = cmd.line (); - if (line < 0) - line = 1; - echo_code (line); - m_echo_file_pos = line + 1; - } - - if (m_debug_mode) - do_breakpoint (cmd.is_active_breakpoint (*this)); - - if (m_in_loop_command) - m_breaking = 1; - else - error ("break must appear in a loop in the same file as loop command"); -} - -void -tree_evaluator::visit_colon_expression (tree_colon_expression&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_continue_command (tree_continue_command& cmd) -{ - if (m_echo_state) - { - int line = cmd.line (); - if (line < 0) - line = 1; - echo_code (line); - m_echo_file_pos = line + 1; - } - - if (m_debug_mode) - do_breakpoint (cmd.is_active_breakpoint (*this)); - - if (m_in_loop_command) - m_continuing = 1; -} - -bool -tree_evaluator::statement_printing_enabled (void) -{ - return ! (m_silent_functions && (m_statement_context == SC_FUNCTION - || m_statement_context == SC_SCRIPT)); -} - -void -tree_evaluator::reset_debug_state (void) -{ - m_debug_mode = (m_bp_table.have_breakpoints () - || m_dbstep_flag != 0 - || m_break_on_next_stmt - || in_debug_repl ()); -} - -void -tree_evaluator::reset_debug_state (bool mode) -{ - m_debug_mode = mode; -} - -void -tree_evaluator::enter_debugger (const std::string& prompt) -{ - unwind_protect frame; - - frame.add (command_history::ignore_entries, - command_history::ignoring_entries ()); - - command_history::ignore_entries (false); - - frame.add (&call_stack::restore_frame, &m_call_stack, - m_call_stack.current_frame ()); - - // Don't allow errors or warnings at the debug prompt to push us - // into deeper levels of debugging. - - error_system& es = m_interpreter.get_error_system (); - - frame.add (&error_system::set_debug_on_error, &es, es.debug_on_error ()); - - frame.add (&error_system::set_debug_on_warning, &es, - es.debug_on_warning ()); - - es.debug_on_error (false); - es.debug_on_warning (false); - - // Go up to the nearest user code frame. - - m_debug_frame = m_call_stack.dbupdown (0); - - // FIXME: probably we just want to print one line, not the - // entire statement, which might span many lines... - // - // tree_print_code tpc (octave_stdout); - // stmt.accept (tpc); - - debugger *dbgr = new debugger (m_interpreter, m_debugger_stack.size ()); - - m_debugger_stack.push (dbgr); - - frame.add ([=] (void) - { - delete m_debugger_stack.top (); - m_debugger_stack.pop (); - reset_debug_state (); - }); - - dbgr->repl (prompt); -} - -void -tree_evaluator::keyboard (const std::string& prompt) -{ - enter_debugger (prompt); -} - -void -tree_evaluator::dbupdown (int n, bool verbose) -{ - m_debug_frame = m_call_stack.dbupdown (n, verbose); -} - -Matrix -tree_evaluator::ignored_fcn_outputs (void) const -{ - Matrix retval; - - const std::list *lvalues = m_lvalue_list; - - if (! lvalues) + } + catch (const std::bad_alloc&) + { + m_interpreter.recover_from_exception (); + m_parser->reset (); + + std::cerr << "error: out of memory -- trying to return to prompt" + << std::endl; + } + } + while (m_exit_status == 0); + + if (m_exit_status == EOF) + { + if (m_interpreter.interactive ()) + octave_stdout << "\n"; + + m_exit_status = 0; + } + + return m_exit_status; + } + + void tree_evaluator::eval (std::shared_ptr& stmt_list, + bool interactive) + { + try + { + stmt_list->accept (*this); + + octave_quit (); + + if (! interactive) + { + bool quit = (m_returning || m_breaking); + + if (m_returning) + m_returning = 0; + + if (m_breaking) + m_breaking--; + + if (quit) + return; + } + + if (octave_completion_matches_called) + octave_completion_matches_called = false; + } + catch (const quit_debug_exception&) + { + m_interpreter.recover_from_exception (); + } + } + + octave_value_list + tree_evaluator::eval_string (const std::string& eval_str, bool silent, + int& parse_status, int nargout) + { + octave_value_list retval; + + parser eval_parser (eval_str, m_interpreter); + + do + { + eval_parser.reset (); + + // If we are looking at + // + // val = eval ("code"); + // + // then don't allow code to be parsed as a command. + + if (nargout > 0) + eval_parser.disallow_command_syntax (); + + parse_status = eval_parser.run (); + + if (parse_status == 0) + { + std::shared_ptr stmt_list + = eval_parser.statement_list (); + + if (stmt_list) + { + tree_statement *stmt = nullptr; + + if (stmt_list->length () == 1 + && (stmt = stmt_list->front ()) + && stmt->is_expression ()) + { + tree_expression *expr = stmt->expression (); + + if (silent) + expr->set_print_flag (false); + + retval = expr->evaluate_n (*this, nargout); + + bool do_bind_ans = false; + + if (expr->is_identifier ()) + do_bind_ans = ! is_variable (expr); + else + do_bind_ans = ! expr->is_assignment_expression (); + + if (do_bind_ans && ! retval.empty ()) + bind_ans (retval(0), expr->print_result ()); + + if (nargout == 0) + retval = octave_value_list (); + } + else if (nargout == 0) + stmt_list->accept (*this); + else + error ("eval: invalid use of statement list"); + + if (returning () || breaking () || continuing ()) + break; + } + else if (eval_parser.at_end_of_input ()) + break; + } + } + while (parse_status == 0); + + return retval; + } + + octave_value tree_evaluator::eval_string (const std::string& eval_str, + bool silent, int& parse_status) + { + octave_value retval; + + octave_value_list tmp = eval_string (eval_str, silent, parse_status, 1); + + if (! tmp.empty ()) + retval = tmp(0); + + return retval; + } + + octave_value_list tree_evaluator::eval_string (const octave_value& arg, + bool silent, int& parse_status, + int nargout) + { + std::string s = arg.xstring_value ("eval: expecting string argument"); + + return eval_string (s, silent, parse_status, nargout); + } + + octave_value_list tree_evaluator::eval (const std::string& try_code, + int nargout) + { + int parse_status = 0; + + return eval_string (try_code, nargout > 0, parse_status, nargout); + } + + octave_value_list tree_evaluator::eval (const std::string& try_code, + const std::string& catch_code, + int nargout) + { + octave_value_list retval; + + error_system& es = m_interpreter.get_error_system (); + + int parse_status = 0; + + bool execution_error = false; + + octave_value_list tmp; + + try + { + tmp = eval_string (try_code, nargout > 0, parse_status, nargout); + } + catch (const execution_exception& ee) + { + es.save_exception (ee); + m_interpreter.recover_from_exception (); + + execution_error = true; + } + + if (parse_status != 0 || execution_error) + { + tmp = eval_string (catch_code, nargout > 0, parse_status, nargout); + + retval = (nargout > 0) ? tmp : octave_value_list (); + } + else + { + if (nargout > 0) + retval = tmp; + + // FIXME: we should really be rethrowing whatever + // exception occurred, not just throwing an + // execution exception. + if (execution_error) + throw execution_exception (); + } + + return retval; + } + + octave_value_list tree_evaluator::evalin (const std::string& context, + const std::string& try_code, + int nargout) + { + unwind_action act ([=] (std::size_t frm) + { + m_call_stack.restore_frame (frm); + }, m_call_stack.current_frame ()); + + if (context == "caller") + m_call_stack.goto_caller_frame (); + else if (context == "base") + m_call_stack.goto_base_frame (); + else + error (R"(evalin: CONTEXT must be "caller" or "base")"); + + int parse_status = 0; + + return eval_string (try_code, nargout > 0, parse_status, nargout); + } + + octave_value_list tree_evaluator::evalin (const std::string& context, + const std::string& try_code, + const std::string& catch_code, + int nargout) + { + octave_value_list retval; + + unwind_action act1 ([=] (std::size_t frm) + { + m_call_stack.restore_frame (frm); + }, m_call_stack.current_frame ()); + + if (context == "caller") + m_call_stack.goto_caller_frame (); + else if (context == "base") + m_call_stack.goto_base_frame (); + else + error (R"(evalin: CONTEXT must be "caller" or "base")"); + + error_system& es = m_interpreter.get_error_system (); + + int parse_status = 0; + + bool execution_error = false; + + octave_value_list tmp; + + try + { + tmp = eval_string (try_code, nargout > 0, parse_status, nargout); + } + catch (const execution_exception& ee) + { + es.save_exception (ee); + m_interpreter.recover_from_exception (); + + execution_error = true; + } + + if (parse_status != 0 || execution_error) + { + tmp = eval_string (catch_code, nargout > 0, parse_status, nargout); + + retval = (nargout > 0) ? tmp : octave_value_list (); + } + else + { + if (nargout > 0) + retval = tmp; + + // FIXME: we should really be rethrowing whatever + // exception occurred, not just throwing an + // execution exception. + if (execution_error) + throw execution_exception (); + } + return retval; - - octave_idx_type nbh = 0; - - for (const auto& lval : *lvalues) - nbh += lval.is_black_hole (); - - if (nbh > 0) - { - retval.resize (1, nbh); - - octave_idx_type k = 0; - octave_idx_type l = 0; - - for (const auto& lval : *lvalues) - { - if (lval.is_black_hole ()) - retval(l++) = k+1; - - k += lval.numel (); - } - } - - return retval; -} - -// If NAME is an operator (like "+", "-", ...), convert it to the -// corresponding function name ("plus", "minus", ...). - -static std::string -get_operator_function_name (const std::string& name) -{ - // Bow to the god of compatibility. - - // FIXME: it seems ugly to put this here, but there is no single - // function in the parser that converts from the operator name to - // the corresponding function name. At least try to do it without N - // string compares. - - // FIXME: .+, .-, **, and .** are deprecated but still need to be - // handled here until they are removed. - - std::size_t len = name.length (); - - if (len == 3 && name == ".**") - // deprecated - return "power"; - else if (len == 2) - { - if (name[0] == '.') - { - switch (name[1]) - { - case '\'': - return "transpose"; - - case '+': - // deprecated - return "plus"; - - case '-': - // deprecated - return "minus"; - - case '*': - return "times"; - - case '/': - return "rdivide"; - - case '^': - return "power"; - - case '\\': - return "ldivide"; - - default: - break; - } - } - else if (name[1] == '=') - { - switch (name[0]) - { - case '<': - return "le"; - - case '=': - return "eq"; - - case '>': - return "ge"; - - case '~': - case '!': - return "ne"; - - default: - break; - } - } - else if (name == "**") - // deprecated - return "mpower"; - } - else if (len == 1) - { - switch (name[0]) - { - case '~': - case '!': - return "not"; - - case '\'': - return "ctranspose"; - - case '+': - return "plus"; - - case '-': - return "minus"; - - case '*': - return "mtimes"; - - case '/': - return "mrdivide"; - - case '^': - return "mpower"; - - case '\\': - return "mldivide"; - - case '<': - return "lt"; - - case '>': - return "gt"; - - case '&': - return "and"; - - case '|': - return "or"; - - default: - break; - } - } - - return name; -} - -// Creates a function handle that takes into account the context, -// finding local, nested, private, or sub functions. - -octave_value -tree_evaluator::make_fcn_handle (const std::string& name) -{ - octave_value retval; - - // The str2func function can create a function handle with the name - // of an operator (for example, "+"). If so, it is converted to the - // name of the corresponding function ("+" -> "plus") and we create - // a simple function handle using that name. - - std::string fcn_name = get_operator_function_name (name); - - // If FCN_NAME is different from NAME, then NAME is an operator. As - // of version 2020a, Matlab apparently uses the function name - // corresponding to the operator to search for private and local - // functions in the current scope but not(!) nested functions. - - bool name_is_operator = fcn_name != name; - - std::size_t pos = fcn_name.find ('.'); - - if (pos != std::string::npos) - { - // Recognize (some of? which ones?) the following cases - // and create something other than a simple function handle? - // Should we just be checking for the last two when the first - // element of the dot-separated list is an object? If so, then - // should this syntax be limited to a dot-separated list with - // exactly two elements? - // - // object . method - // object . static-method - // - // Code to do that duplicates some of simple_fcn_handle::call. - - // Only accept expressions that contain one '.' separator. - - // FIXME: The logic here is a bit complicated. Is there a good - // way to simplify it? - - std::string meth_nm = fcn_name.substr (pos+1); - - if (meth_nm.find ('.') == std::string::npos) - { - std::string obj_nm = fcn_name.substr (0, pos); - - // If obj_nm is an object in the current scope with a - // method named meth_nm, create a classsimple handle. - - octave_value object = varval (obj_nm); - - if (object.is_defined () && object.is_classdef_object ()) - { - octave_classdef *cdef = object.classdef_object_value (); - - if (cdef) - { - std::string class_nm = cdef->class_name (); - - cdef_object cdef_obj = cdef->get_object (); - - cdef_class cls = cdef_obj.get_class (); - - cdef_method meth = cls.find_method (meth_nm); - - if (meth.ok ()) - { - // If the method we found is static, create a - // new function name from the class name and - // method name and create a simple function - // handle below. Otherwise, create a class - // simple function handle. - - if (meth.is_static ()) - fcn_name = class_nm + '.' + meth_nm; - else - { - octave_value meth_fcn = meth.get_function (); - - octave_fcn_handle *fh - = new octave_fcn_handle (object, meth_fcn, - class_nm, meth_nm); - - return octave_value (fh); - } - } - } - } - } - - // We didn't match anything above, so create handle to SIMPLE - // package function or static class method. Function resolution - // is performed when the handle is used. - - return octave_value (new octave_fcn_handle (fcn_name)); - } - - // If the function name refers to a sub/local/private function or a - // class method/constructor, create scoped function handle that is - // bound to that function. Use the same precedence list as - // fcn_info::find but limit search to the following types of - // functions: - // - // nested functions (and subfunctions) - // local functions in the current file - // private function - // class method - // - // For anything else we create a simple function handle that will be - // resolved dynamically in the scope where it is evaluated. - - symbol_scope curr_scope = get_current_scope (); - - symbol_table& symtab = m_interpreter.get_symbol_table (); - - if (curr_scope) - { - octave_value ov_fcn - = symtab.find_scoped_function (fcn_name, curr_scope); - - // If name is operator, we are in Fstr2func, so skip the stack - // frame for that function. - - bool skip_first = name_is_operator; - octave_function *curr_fcn = current_function (skip_first); - - if (ov_fcn.is_defined ()) - { - octave_function *fcn = ov_fcn.function_value (); - - if (fcn->is_nested_function ()) - { - if (! name_is_operator) - { - // Get current stack frame and return handle to nested - // function. - - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - // If we are creating a handle to the current - // function or a handle to a sibling function (i.e., - // not a child of the current function), then use - // the calling stack frame as the context instead of - // the current stack frame. - - // FIXME: Do we need both checks here or is it - // sufficient to check that the parent of curr_fcn - // is the same as the parent of fcn? Is there any - // case where curr_fcn could be nullptr, or does - // that indicate an internal error of some kind? - - if (curr_fcn - && (fcn_name == curr_fcn->name () - || fcn->parent_fcn_name () == curr_fcn->parent_fcn_name ())) - frame = frame->access_link (); - - octave_fcn_handle *fh - = new octave_fcn_handle (ov_fcn, fcn_name, frame); - - return octave_value (fh); - } - } - else if (fcn->is_subfunction () - /* || fcn->is_localfunction () */ - || fcn->is_private_function ()) - { - // Create handle to SCOPED function (sub/local function - // or private function). - - std::list parentage = fcn->parent_fcn_names (); - - octave_fcn_handle *fh - = new octave_fcn_handle (ov_fcn, fcn_name, parentage); - - return octave_value (fh); - } - } - - if (curr_fcn && (curr_fcn->is_class_method () - || curr_fcn->is_class_constructor ())) - { - std::string dispatch_class = curr_fcn->dispatch_class (); - - octave_value ov_meth - = symtab.find_method (fcn_name, dispatch_class); - - if (ov_meth.is_defined ()) - { - octave_function *fcn = ov_meth.function_value (); - - // FIXME: do we need to check that it is a method of - // dispatch_class, or is it sufficient to just check - // that it is a method? - - if (fcn->is_class_method ()) - { - // Create CLASSSIMPLE handle to method but don't - // bind to the method. Lookup will be done later. - - octave_fcn_handle *fh - = new octave_fcn_handle (dispatch_class, fcn_name); - - return octave_value (fh); - } - } - } - } - - octave_value ov_fcn = symtab.find_user_function (fcn_name); - - // Create handle to SIMPLE function. If the function is not found - // now, then we will look for it again when the handle is used. - - return octave_value (new octave_fcn_handle (ov_fcn, fcn_name)); -} + } + + void + tree_evaluator::visit_anon_fcn_handle (tree_anon_fcn_handle&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_argument_list (tree_argument_list&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_arguments_block (tree_arguments_block&) + { + warning ("function arguments validation blocks are not supported; INCORRECT RESULTS ARE POSSIBLE"); + } + + void + tree_evaluator::visit_args_block_attribute_list (tree_args_block_attribute_list&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_args_block_validation_list (tree_args_block_validation_list&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_arg_validation (tree_arg_validation&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_arg_size_spec (tree_arg_size_spec&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_arg_validation_fcns (tree_arg_validation_fcns&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_binary_expression (tree_binary_expression&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_boolean_expression (tree_boolean_expression&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_compound_binary_expression (tree_compound_binary_expression&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_break_command (tree_break_command& cmd) + { + if (m_echo_state) + { + int line = cmd.line (); + if (line < 0) + line = 1; + echo_code (line); + m_echo_file_pos = line + 1; + } + + if (m_debug_mode) + do_breakpoint (cmd.is_active_breakpoint (*this)); + + if (m_in_loop_command) + m_breaking = 1; + else + error ("break must appear in a loop in the same file as loop command"); + } + + void + tree_evaluator::visit_colon_expression (tree_colon_expression&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_continue_command (tree_continue_command& cmd) + { + if (m_echo_state) + { + int line = cmd.line (); + if (line < 0) + line = 1; + echo_code (line); + m_echo_file_pos = line + 1; + } + + if (m_debug_mode) + do_breakpoint (cmd.is_active_breakpoint (*this)); + + if (m_in_loop_command) + m_continuing = 1; + } + + bool + tree_evaluator::statement_printing_enabled (void) + { + return ! (m_silent_functions && (m_statement_context == SC_FUNCTION + || m_statement_context == SC_SCRIPT)); + } + + void + tree_evaluator::reset_debug_state (void) + { + m_debug_mode = (m_bp_table.have_breakpoints () + || m_dbstep_flag != 0 + || m_break_on_next_stmt + || in_debug_repl ()); + } + + void + tree_evaluator::reset_debug_state (bool mode) + { + m_debug_mode = mode; + } + + void + tree_evaluator::enter_debugger (const std::string& prompt) + { + unwind_protect frame; + + frame.add (command_history::ignore_entries, + command_history::ignoring_entries ()); + + command_history::ignore_entries (false); + + frame.add (&call_stack::restore_frame, &m_call_stack, + m_call_stack.current_frame ()); + + // Don't allow errors or warnings at the debug prompt to push us + // into deeper levels of debugging. + + error_system& es = m_interpreter.get_error_system (); + + frame.add (&error_system::set_debug_on_error, &es, es.debug_on_error ()); + + frame.add (&error_system::set_debug_on_warning, &es, + es.debug_on_warning ()); + + es.debug_on_error (false); + es.debug_on_warning (false); + + // Go up to the nearest user code frame. + + m_debug_frame = m_call_stack.dbupdown (0); + + // FIXME: probably we just want to print one line, not the + // entire statement, which might span many lines... + // + // tree_print_code tpc (octave_stdout); + // stmt.accept (tpc); + + debugger *dbgr = new debugger (m_interpreter, m_debugger_stack.size ()); + + m_debugger_stack.push (dbgr); + + frame.add ([=] (void) + { + delete m_debugger_stack.top (); + m_debugger_stack.pop (); + reset_debug_state (); + }); + + dbgr->repl (prompt); + } + + void + tree_evaluator::keyboard (const std::string& prompt) + { + enter_debugger (prompt); + } + + void + tree_evaluator::dbupdown (int n, bool verbose) + { + m_debug_frame = m_call_stack.dbupdown (n, verbose); + } + + Matrix + tree_evaluator::ignored_fcn_outputs (void) const + { + Matrix retval; + + const std::list *lvalues = m_lvalue_list; + + if (! lvalues) + return retval; + + octave_idx_type nbh = 0; + + for (const auto& lval : *lvalues) + nbh += lval.is_black_hole (); + + if (nbh > 0) + { + retval.resize (1, nbh); + + octave_idx_type k = 0; + octave_idx_type l = 0; + + for (const auto& lval : *lvalues) + { + if (lval.is_black_hole ()) + retval(l++) = k+1; + + k += lval.numel (); + } + } + + return retval; + } + + // If NAME is an operator (like "+", "-", ...), convert it to the + // corresponding function name ("plus", "minus", ...). + + static std::string + get_operator_function_name (const std::string& name) + { + // Bow to the god of compatibility. + + // FIXME: it seems ugly to put this here, but there is no single + // function in the parser that converts from the operator name to + // the corresponding function name. At least try to do it without N + // string compares. + + std::size_t len = name.length (); + + if (len == 2) + { + if (name[0] == '.') + { + switch (name[1]) + { + case '\'': + return "transpose"; + + case '*': + return "times"; + + case '/': + return "rdivide"; + + case '^': + return "power"; + + case '\\': + return "ldivide"; + + default: + break; + } + } + else if (name[1] == '=') + { + switch (name[0]) + { + case '<': + return "le"; + + case '=': + return "eq"; + + case '>': + return "ge"; + + case '~': + case '!': + return "ne"; + + default: + break; + } + } + } + else if (len == 1) + { + switch (name[0]) + { + case '~': + case '!': + return "not"; + + case '\'': + return "ctranspose"; + + case '+': + return "plus"; + + case '-': + return "minus"; + + case '*': + return "mtimes"; + + case '/': + return "mrdivide"; + + case '^': + return "mpower"; + + case '\\': + return "mldivide"; + + case '<': + return "lt"; + + case '>': + return "gt"; + + case '&': + return "and"; + + case '|': + return "or"; + + default: + break; + } + } + + return name; + } + + // Creates a function handle that takes into account the context, + // finding local, nested, private, or sub functions. + + octave_value + tree_evaluator::make_fcn_handle (const std::string& name) + { + octave_value retval; + + // The str2func function can create a function handle with the name + // of an operator (for example, "+"). If so, it is converted to the + // name of the corresponding function ("+" -> "plus") and we create + // a simple function handle using that name. + + std::string fcn_name = get_operator_function_name (name); + + // If FCN_NAME is different from NAME, then NAME is an operator. As + // of version 2020a, Matlab apparently uses the function name + // corresponding to the operator to search for private and local + // functions in the current scope but not(!) nested functions. + + bool name_is_operator = fcn_name != name; + + std::size_t pos = fcn_name.find ('.'); + + if (pos != std::string::npos) + { + // Recognize (some of? which ones?) the following cases + // and create something other than a simple function handle? + // Should we just be checking for the last two when the first + // element of the dot-separated list is an object? If so, then + // should this syntax be limited to a dot-separated list with + // exactly two elements? + // + // object . method + // object . static-method + // + // Code to do that duplicates some of simple_fcn_handle::call. + + // Only accept expressions that contain one '.' separator. + + // FIXME: The logic here is a bit complicated. Is there a good + // way to simplify it? + + std::string meth_nm = fcn_name.substr (pos+1); + + if (meth_nm.find ('.') == std::string::npos) + { + std::string obj_nm = fcn_name.substr (0, pos); + + // If obj_nm is an object in the current scope with a + // method named meth_nm, create a classsimple handle. + + octave_value object = varval (obj_nm); + + if (object.is_defined () && object.is_classdef_object ()) + { + octave_classdef *cdef = object.classdef_object_value (); + + if (cdef) + { + std::string class_nm = cdef->class_name (); + + cdef_object cdef_obj = cdef->get_object (); + + cdef_class cls = cdef_obj.get_class (); + + cdef_method meth = cls.find_method (meth_nm); + + if (meth.ok ()) + { + // If the method we found is static, create a + // new function name from the class name and + // method name and create a simple function + // handle below. Otherwise, create a class + // simple function handle. + + if (meth.is_static ()) + fcn_name = class_nm + '.' + meth_nm; + else + { + octave_value meth_fcn = meth.get_function (); + + octave_fcn_handle *fh + = new octave_fcn_handle (object, meth_fcn, + class_nm, meth_nm); + + return octave_value (fh); + } + } + } + } + } + + // We didn't match anything above, so create handle to SIMPLE + // package function or static class method. Function resolution + // is performed when the handle is used. + + return octave_value (new octave_fcn_handle (fcn_name)); + } + + // If the function name refers to a sub/local/private function or a + // class method/constructor, create scoped function handle that is + // bound to that function. Use the same precedence list as + // fcn_info::find but limit search to the following types of + // functions: + // + // nested functions (and subfunctions) + // local functions in the current file + // private function + // class method + // + // For anything else we create a simple function handle that will be + // resolved dynamically in the scope where it is evaluated. + + symbol_scope curr_scope = get_current_scope (); + + symbol_table& symtab = m_interpreter.get_symbol_table (); + + if (curr_scope) + { + octave_value ov_fcn + = symtab.find_scoped_function (fcn_name, curr_scope); + + // If name is operator, we are in Fstr2func, so skip the stack + // frame for that function. + + bool skip_first = name_is_operator; + octave_function *curr_fcn = current_function (skip_first); + + if (ov_fcn.is_defined ()) + { + octave_function *fcn = ov_fcn.function_value (); + + if (fcn->is_nested_function ()) + { + if (! name_is_operator) + { + // Get current stack frame and return handle to nested + // function. + + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + // If we are creating a handle to the current + // function or a handle to a sibling function (i.e., + // not a child of the current function), then use + // the calling stack frame as the context instead of + // the current stack frame. + + // FIXME: Do we need both checks here or is it + // sufficient to check that the parent of curr_fcn + // is the same as the parent of fcn? Is there any + // case where curr_fcn could be nullptr, or does + // that indicate an internal error of some kind? + + if (curr_fcn + && (fcn_name == curr_fcn->name () + || fcn->parent_fcn_name () == curr_fcn->parent_fcn_name ())) + frame = frame->access_link (); + + octave_fcn_handle *fh + = new octave_fcn_handle (ov_fcn, fcn_name, frame); + + return octave_value (fh); + } + } + else if (fcn->is_subfunction () + /* || fcn->is_localfunction () */ + || fcn->is_private_function ()) + { + // Create handle to SCOPED function (sub/local function + // or private function). + + std::list parentage = fcn->parent_fcn_names (); + + octave_fcn_handle *fh + = new octave_fcn_handle (ov_fcn, fcn_name, parentage); + + return octave_value (fh); + } + } + + if (curr_fcn && (curr_fcn->is_class_method () + || curr_fcn->is_class_constructor ())) + { + std::string dispatch_class = curr_fcn->dispatch_class (); + + octave_value ov_meth + = symtab.find_method (fcn_name, dispatch_class); + + if (ov_meth.is_defined ()) + { + octave_function *fcn = ov_meth.function_value (); + + // FIXME: do we need to check that it is a method of + // dispatch_class, or is it sufficient to just check + // that it is a method? + + if (fcn->is_class_method ()) + { + // Create CLASSSIMPLE handle to method but don't + // bind to the method. Lookup will be done later. + + octave_fcn_handle *fh + = new octave_fcn_handle (dispatch_class, fcn_name); + + return octave_value (fh); + } + } + } + } + + octave_value ov_fcn = symtab.find_user_function (fcn_name); + + // Create handle to SIMPLE function. If the function is not found + // now, then we will look for it again when the handle is used. + + return octave_value (new octave_fcn_handle (ov_fcn, fcn_name)); + } /* %!test -%! x = {".**", "power"; -%! ".'", "transpose"; -%! ".+", "plus"; -%! ".-", "minus"; +%! x = {".'", "transpose"; %! ".*", "times"; %! "./", "rdivide"; %! ".^", "power"; @@ -1833,7 +1813,6 @@ %! ">=", "ge"; %! "!=", "ne"; %! "~=", "ne"; -%! "**", "mpower"; %! "~", "not"; %! "!", "not"; %! "\'", "ctranspose"; @@ -1852,401 +1831,401 @@ %! endfor */ -octave_value -tree_evaluator::evaluate (tree_decl_elt *elt) -{ - // Do not allow functions to return null values. - - tree_identifier *id = elt->ident (); - - return id ? id->evaluate (*this).storable_value () : octave_value (); -} - -bool -tree_evaluator::is_variable (const std::string& name) const -{ - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - return frame->is_variable (name); -} - -bool -tree_evaluator::is_local_variable (const std::string& name) const -{ - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - return frame->is_local_variable (name); -} - -bool -tree_evaluator::is_variable (const tree_expression *expr) const -{ - if (expr->is_identifier ()) - { - const tree_identifier *id - = dynamic_cast (expr); - - if (id->is_black_hole ()) - return false; - - return is_variable (id->symbol ()); - } - - return false; -} - -bool -tree_evaluator::is_defined (const tree_expression *expr) const -{ - if (expr->is_identifier ()) - { - const tree_identifier *id - = dynamic_cast (expr); - - return is_defined (id->symbol ()); - } - - return false; -} - -bool -tree_evaluator::is_variable (const symbol_record& sym) const -{ - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - return frame->is_variable (sym); -} - -bool -tree_evaluator::is_defined (const symbol_record& sym) const -{ - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - return frame->is_defined (sym); -} - -bool tree_evaluator::is_global (const std::string& name) const -{ - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - return frame->is_global (name); -} - -octave_value -tree_evaluator::varval (const symbol_record& sym) const -{ - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - return frame->varval (sym); -} - -octave_value -tree_evaluator::varval (const std::string& name) const -{ - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - return frame->varval (name); -} - -void tree_evaluator::install_variable (const std::string& name, - const octave_value& value, - bool global) -{ - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - return frame->install_variable (name, value, global); -} - -octave_value -tree_evaluator::global_varval (const std::string& name) const -{ - return m_call_stack.global_varval (name); -} - -octave_value& -tree_evaluator::global_varref (const std::string& name) -{ - return m_call_stack.global_varref (name); -} - -void -tree_evaluator::global_assign (const std::string& name, - const octave_value& val) -{ - m_call_stack.global_varref (name) = val; -} - -octave_value -tree_evaluator::top_level_varval (const std::string& name) const -{ - return m_call_stack.get_top_level_value (name); -} - -void -tree_evaluator::top_level_assign (const std::string& name, - const octave_value& val) -{ - m_call_stack.set_top_level_value (name, val); -} - -void -tree_evaluator::assign (const std::string& name, const octave_value& val) -{ - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - frame->assign (name, val); -} - -void -tree_evaluator::assignin (const std::string& context, - const std::string& name, const octave_value& val) -{ - // FIXME: Can this be done without an unwind-protect frame, simply - // by getting a reference to the caller or base stack frame and - // calling assign on that? - - unwind_action act ([=] (std::size_t frm) - { - m_call_stack.restore_frame (frm); - }, m_call_stack.current_frame ()); - - if (context == "caller") - m_call_stack.goto_caller_frame (); - else if (context == "base") - m_call_stack.goto_base_frame (); - else - error (R"(assignin: CONTEXT must be "caller" or "base")"); - - if (valid_identifier (name)) - { - // Put the check here so that we don't slow down assignments - // generally. Any that go through Octave's parser should have - // already been checked. - - if (iskeyword (name)) - error ("assignin: invalid assignment to keyword '%s'", - name.c_str ()); - - assign (name, val); - } - else - error ("assignin: invalid variable name '%s'", name.c_str ()); -} - -void -tree_evaluator::source_file (const std::string& file_name, - const std::string& context, - bool verbose, bool require_file) -{ - // Map from absolute name of script file to recursion level. We - // use a map instead of simply placing a limit on recursion in the - // source_file function so that two mutually recursive scripts - // written as - // - // foo1.m: - // ------ - // foo2 - // - // foo2.m: - // ------ - // foo1 - // - // and called with - // - // foo1 - // - // (for example) will behave the same if they are written as - // - // foo1.m: - // ------ - // source ("foo2.m") - // - // foo2.m: - // ------ - // source ("foo1.m") - // - // and called with - // - // source ("foo1.m") - // - // (for example). - - static std::map source_call_depth; - - std::string file_full_name - = sys::file_ops::tilde_expand (file_name); - - std::size_t pos - = file_full_name.find_last_of (sys::file_ops::dir_sep_str ()); - - std::string dir_name = file_full_name.substr (0, pos); - - file_full_name = sys::env::make_absolute (file_full_name); - - unwind_protect frame; - - if (source_call_depth.find (file_full_name) == source_call_depth.end ()) - source_call_depth[file_full_name] = -1; - - frame.protect_var (source_call_depth[file_full_name]); - - source_call_depth[file_full_name]++; - - if (source_call_depth[file_full_name] >= max_recursion_depth ()) - error ("max_recursion_depth exceeded"); - - if (! context.empty ()) - { - frame.add (&call_stack::restore_frame, &m_call_stack, - m_call_stack.current_frame ()); - - if (context == "caller") - m_call_stack.goto_caller_frame (); - else if (context == "base") - m_call_stack.goto_base_frame (); - else - error (R"(source: CONTEXT must be "caller" or "base")"); - } - - // Find symbol name that would be in symbol_table, if it were loaded. - std::size_t dir_end - = file_name.find_last_of (sys::file_ops::dir_sep_chars ()); - dir_end = (dir_end == std::string::npos) ? 0 : dir_end + 1; - - std::size_t extension = file_name.find_last_of ('.'); - if (extension == std::string::npos) - extension = file_name.length (); - - std::string symbol = file_name.substr (dir_end, extension - dir_end); - std::string full_name = sys::canonicalize_file_name (file_name); - - // Check if this file is already loaded (or in the path) - symbol_table& symtab = m_interpreter.get_symbol_table (); - octave_value ov_code = symtab.fcn_table_find (symbol); - - // For compatibility with Matlab, accept both scripts and - // functions. - - if (ov_code.is_user_code ()) - { - octave_user_code *code = ov_code.user_code_value (); - - if (! code - || (sys::canonicalize_file_name (code->fcn_file_name ()) - != full_name)) - { - // Wrong file, so load it below. - ov_code = octave_value (); - } - } - else - { - // Not a script, so load it below. - ov_code = octave_value (); - } - - // If no symbol of this name, or the symbol is for a different - // file, load. - - if (ov_code.is_undefined ()) - { - try - { - ov_code = parse_fcn_file (m_interpreter, file_full_name, - file_name, dir_name, "", "", - require_file, true, false, false); - } - catch (execution_exception& ee) - { - error (ee, "source: error sourcing file '%s'", - file_full_name.c_str ()); - } - } - - // Return or error if we don't have a valid script or function. - - if (ov_code.is_undefined ()) - return; - - if (! ov_code.is_user_code ()) - error ("source: %s is not a script", full_name.c_str ()); - - if (verbose) - { - octave_stdout << "executing commands from " << full_name << " ... "; - octave_stdout.flush (); - } - - octave_user_code *code = ov_code.user_code_value (); - - code->call (*this, 0, octave_value_list ()); - - if (verbose) - octave_stdout << "done." << std::endl; -} - -void -tree_evaluator::set_auto_fcn_var (stack_frame::auto_var_type avt, - const octave_value& val) -{ - m_call_stack.set_auto_fcn_var (avt, val); -} - -octave_value -tree_evaluator::get_auto_fcn_var (stack_frame::auto_var_type avt) const -{ - return m_call_stack.get_auto_fcn_var (avt); -} - -void -tree_evaluator::define_parameter_list_from_arg_vector -(tree_parameter_list *param_list, const octave_value_list& args) -{ - if (! param_list || param_list->varargs_only ()) - return; - - int i = -1; - - for (tree_decl_elt *elt : *param_list) - { - i++; - - octave_lvalue ref = elt->lvalue (*this); - - if (i < args.length ()) - { - if (args(i).is_defined () && args(i).is_magic_colon ()) - { - if (! eval_decl_elt (elt)) - error ("no default value for argument %d", i+1); - } - else - ref.define (args(i)); - } - else - eval_decl_elt (elt); - } -} - -void -tree_evaluator::undefine_parameter_list (tree_parameter_list *param_list) -{ - for (tree_decl_elt *elt : *param_list) - { - octave_lvalue ref = elt->lvalue (*this); - - ref.assign (octave_value::op_asn_eq, octave_value ()); - } -} + octave_value + tree_evaluator::evaluate (tree_decl_elt *elt) + { + // Do not allow functions to return null values. + + tree_identifier *id = elt->ident (); + + return id ? id->evaluate (*this).storable_value () : octave_value (); + } + + bool + tree_evaluator::is_variable (const std::string& name) const + { + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + return frame->is_variable (name); + } + + bool + tree_evaluator::is_local_variable (const std::string& name) const + { + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + return frame->is_local_variable (name); + } + + bool + tree_evaluator::is_variable (const tree_expression *expr) const + { + if (expr->is_identifier ()) + { + const tree_identifier *id + = dynamic_cast (expr); + + if (id->is_black_hole ()) + return false; + + return is_variable (id->symbol ()); + } + + return false; + } + + bool + tree_evaluator::is_defined (const tree_expression *expr) const + { + if (expr->is_identifier ()) + { + const tree_identifier *id + = dynamic_cast (expr); + + return is_defined (id->symbol ()); + } + + return false; + } + + bool + tree_evaluator::is_variable (const symbol_record& sym) const + { + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + return frame->is_variable (sym); + } + + bool + tree_evaluator::is_defined (const symbol_record& sym) const + { + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + return frame->is_defined (sym); + } + + bool tree_evaluator::is_global (const std::string& name) const + { + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + return frame->is_global (name); + } + + octave_value + tree_evaluator::varval (const symbol_record& sym) const + { + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + return frame->varval (sym); + } + + octave_value + tree_evaluator::varval (const std::string& name) const + { + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + return frame->varval (name); + } + + void tree_evaluator::install_variable (const std::string& name, + const octave_value& value, + bool global) + { + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + return frame->install_variable (name, value, global); + } + + octave_value + tree_evaluator::global_varval (const std::string& name) const + { + return m_call_stack.global_varval (name); + } + + octave_value& + tree_evaluator::global_varref (const std::string& name) + { + return m_call_stack.global_varref (name); + } + + void + tree_evaluator::global_assign (const std::string& name, + const octave_value& val) + { + m_call_stack.global_varref (name) = val; + } + + octave_value + tree_evaluator::top_level_varval (const std::string& name) const + { + return m_call_stack.get_top_level_value (name); + } + + void + tree_evaluator::top_level_assign (const std::string& name, + const octave_value& val) + { + m_call_stack.set_top_level_value (name, val); + } + + void + tree_evaluator::assign (const std::string& name, const octave_value& val) + { + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + frame->assign (name, val); + } + + void + tree_evaluator::assignin (const std::string& context, + const std::string& name, const octave_value& val) + { + // FIXME: Can this be done without an unwind-protect frame, simply + // by getting a reference to the caller or base stack frame and + // calling assign on that? + + unwind_action act ([=] (std::size_t frm) + { + m_call_stack.restore_frame (frm); + }, m_call_stack.current_frame ()); + + if (context == "caller") + m_call_stack.goto_caller_frame (); + else if (context == "base") + m_call_stack.goto_base_frame (); + else + error (R"(assignin: CONTEXT must be "caller" or "base")"); + + if (valid_identifier (name)) + { + // Put the check here so that we don't slow down assignments + // generally. Any that go through Octave's parser should have + // already been checked. + + if (iskeyword (name)) + error ("assignin: invalid assignment to keyword '%s'", + name.c_str ()); + + assign (name, val); + } + else + error ("assignin: invalid variable name '%s'", name.c_str ()); + } + + void + tree_evaluator::source_file (const std::string& file_name, + const std::string& context, + bool verbose, bool require_file) + { + // Map from absolute name of script file to recursion level. We + // use a map instead of simply placing a limit on recursion in the + // source_file function so that two mutually recursive scripts + // written as + // + // foo1.m: + // ------ + // foo2 + // + // foo2.m: + // ------ + // foo1 + // + // and called with + // + // foo1 + // + // (for example) will behave the same if they are written as + // + // foo1.m: + // ------ + // source ("foo2.m") + // + // foo2.m: + // ------ + // source ("foo1.m") + // + // and called with + // + // source ("foo1.m") + // + // (for example). + + static std::map source_call_depth; + + std::string file_full_name + = sys::file_ops::tilde_expand (file_name); + + std::size_t pos + = file_full_name.find_last_of (sys::file_ops::dir_sep_str ()); + + std::string dir_name = file_full_name.substr (0, pos); + + file_full_name = sys::env::make_absolute (file_full_name); + + unwind_protect frame; + + if (source_call_depth.find (file_full_name) == source_call_depth.end ()) + source_call_depth[file_full_name] = -1; + + frame.protect_var (source_call_depth[file_full_name]); + + source_call_depth[file_full_name]++; + + if (source_call_depth[file_full_name] >= max_recursion_depth ()) + error ("max_recursion_depth exceeded"); + + if (! context.empty ()) + { + frame.add (&call_stack::restore_frame, &m_call_stack, + m_call_stack.current_frame ()); + + if (context == "caller") + m_call_stack.goto_caller_frame (); + else if (context == "base") + m_call_stack.goto_base_frame (); + else + error (R"(source: CONTEXT must be "caller" or "base")"); + } + + // Find symbol name that would be in symbol_table, if it were loaded. + std::size_t dir_end + = file_name.find_last_of (sys::file_ops::dir_sep_chars ()); + dir_end = (dir_end == std::string::npos) ? 0 : dir_end + 1; + + std::size_t extension = file_name.find_last_of ('.'); + if (extension == std::string::npos) + extension = file_name.length (); + + std::string symbol = file_name.substr (dir_end, extension - dir_end); + std::string full_name = sys::canonicalize_file_name (file_name); + + // Check if this file is already loaded (or in the path) + symbol_table& symtab = m_interpreter.get_symbol_table (); + octave_value ov_code = symtab.fcn_table_find (symbol); + + // For compatibility with Matlab, accept both scripts and + // functions. + + if (ov_code.is_user_code ()) + { + octave_user_code *code = ov_code.user_code_value (); + + if (! code + || (sys::canonicalize_file_name (code->fcn_file_name ()) + != full_name)) + { + // Wrong file, so load it below. + ov_code = octave_value (); + } + } + else + { + // Not a script, so load it below. + ov_code = octave_value (); + } + + // If no symbol of this name, or the symbol is for a different + // file, load. + + if (ov_code.is_undefined ()) + { + try + { + ov_code = parse_fcn_file (m_interpreter, file_full_name, + file_name, dir_name, "", "", + require_file, true, false, false); + } + catch (execution_exception& ee) + { + error (ee, "source: error sourcing file '%s'", + file_full_name.c_str ()); + } + } + + // Return or error if we don't have a valid script or function. + + if (ov_code.is_undefined ()) + return; + + if (! ov_code.is_user_code ()) + error ("source: %s is not a script", full_name.c_str ()); + + if (verbose) + { + octave_stdout << "executing commands from " << full_name << " ... "; + octave_stdout.flush (); + } + + octave_user_code *code = ov_code.user_code_value (); + + code->call (*this, 0, octave_value_list ()); + + if (verbose) + octave_stdout << "done." << std::endl; + } + + void + tree_evaluator::set_auto_fcn_var (stack_frame::auto_var_type avt, + const octave_value& val) + { + m_call_stack.set_auto_fcn_var (avt, val); + } + + octave_value + tree_evaluator::get_auto_fcn_var (stack_frame::auto_var_type avt) const + { + return m_call_stack.get_auto_fcn_var (avt); + } + + void + tree_evaluator::define_parameter_list_from_arg_vector + (tree_parameter_list *param_list, const octave_value_list& args) + { + if (! param_list || param_list->varargs_only ()) + return; + + int i = -1; + + for (tree_decl_elt *elt : *param_list) + { + i++; + + octave_lvalue ref = elt->lvalue (*this); + + if (i < args.length ()) + { + if (args(i).is_defined () && args(i).is_magic_colon ()) + { + if (! eval_decl_elt (elt)) + error ("no default value for argument %d", i+1); + } + else + ref.define (args(i)); + } + else + eval_decl_elt (elt); + } + } + + void + tree_evaluator::undefine_parameter_list (tree_parameter_list *param_list) + { + for (tree_decl_elt *elt : *param_list) + { + octave_lvalue ref = elt->lvalue (*this); + + ref.assign (octave_value::op_asn_eq, octave_value ()); + } + } // END is documented in op-kw-docs. DEFMETHOD (end, interp, args, , @@ -2292,2989 +2271,2988 @@ %! assert (x(minus (minus (end, 1), 1)), 8); */ -octave_value_list -tree_evaluator::convert_to_const_vector (tree_argument_list *args) -{ - std::list arg_vals; - - for (auto elt : *args) - { - // FIXME: is it possible for elt to be invalid? - - if (! elt) + octave_value_list + tree_evaluator::convert_to_const_vector (tree_argument_list *args) + { + std::list arg_vals; + + for (auto elt : *args) + { + // FIXME: is it possible for elt to be invalid? + + if (! elt) + break; + + octave_value tmp = elt->evaluate (*this); + + if (tmp.is_cs_list ()) + { + octave_value_list tmp_ovl = tmp.list_value (); + + for (octave_idx_type i = 0; i < tmp_ovl.length (); i++) + arg_vals.push_back (tmp_ovl(i)); + } + else if (tmp.is_defined ()) + arg_vals.push_back (tmp); + } + + return octave_value_list (arg_vals); + } + + octave_value_list + tree_evaluator::convert_return_list_to_const_vector + (tree_parameter_list *ret_list, int nargout, const Matrix& ignored_outputs, + const Cell& varargout) + { + octave_idx_type vlen = varargout.numel (); + int len = ret_list->length (); + + // Special case. Will do a shallow copy. + if (len == 0) + return varargout; + else + { + int i = 0; + int k = 0; + int num_ignored = ignored_outputs.numel (); + int ignored = num_ignored > 0 ? ignored_outputs(k) - 1 : -1; + + if (nargout <= len) + { + int nout = nargout > 0 ? nargout : 1; + octave_value_list retval (nout); + + for (tree_decl_elt *elt : *ret_list) + { + if (nargout == 0 && ! is_defined (elt->ident ())) + break; + + if (ignored >= 0 && i == ignored) + { + i++; + k++; + ignored = k < num_ignored ? ignored_outputs(k) - 1 : -1; + } + else + retval(i++) = evaluate (elt); + + if (i == nout) + break; + } + + return retval; + } + else + { + octave_value_list retval (len + vlen); + + for (tree_decl_elt *elt : *ret_list) + { + if (ignored >= 0 && i == ignored) + { + i++; + k++; + ignored = k < num_ignored ? ignored_outputs(k) - 1 : -1; + } + else + retval(i++) = evaluate (elt); + } + + for (octave_idx_type j = 0; j < vlen; j++) + retval(i++) = varargout(j); + + return retval; + } + } + } + + bool + tree_evaluator::eval_decl_elt (tree_decl_elt *elt) + { + bool retval = false; + + tree_identifier *id = elt->ident (); + tree_expression *expr = elt->expression (); + + if (id && expr) + { + octave_lvalue ult = id->lvalue (*this); + + octave_value init_val = expr->evaluate (*this); + + ult.assign (octave_value::op_asn_eq, init_val); + + retval = true; + } + + return retval; + } + + bool + tree_evaluator::switch_case_label_matches (tree_switch_case *expr, + const octave_value& val) + { + tree_expression *label = expr->case_label (); + + octave_value label_value = label->evaluate (*this); + + if (label_value.is_defined ()) + { + if (label_value.iscell ()) + { + Cell cell (label_value.cell_value ()); + + for (octave_idx_type i = 0; i < cell.rows (); i++) + { + for (octave_idx_type j = 0; j < cell.columns (); j++) + { + bool match = val.is_equal (cell(i,j)); + + if (match) + return true; + } + } + } + else + return val.is_equal (label_value); + } + + return false; + } + + void tree_evaluator::push_stack_frame (const symbol_scope& scope) + { + m_call_stack.push (scope); + } + + void tree_evaluator::push_stack_frame (octave_user_function *fcn, + const std::shared_ptr& closure_frames) + { + m_call_stack.push (fcn, closure_frames); + } + + void tree_evaluator::push_stack_frame (octave_user_function *fcn, + const stack_frame::local_vars_map& local_vars, + const std::shared_ptr& closure_frames) + { + m_call_stack.push (fcn, local_vars, closure_frames); + } + + void tree_evaluator::push_stack_frame (octave_user_script *script) + { + m_call_stack.push (script); + } + + void tree_evaluator::push_stack_frame (octave_function *fcn) + { + m_call_stack.push (fcn); + } + + void tree_evaluator::pop_stack_frame (void) + { + m_call_stack.pop (); + } + + int tree_evaluator::current_line (void) const + { + return m_call_stack.current_line (); + } + + int tree_evaluator::current_column (void) const + { + return m_call_stack.current_column (); + } + + int tree_evaluator::debug_user_code_line (void) const + { + return m_call_stack.debug_user_code_line (); + } + + int tree_evaluator::debug_user_code_column (void) const + { + return m_call_stack.debug_user_code_column (); + } + + void tree_evaluator::debug_where (std::ostream& os) const + { + std::shared_ptr frm = m_call_stack.current_user_frame (); + + frm->display_stopped_in_message (os); + } + + octave_user_code * tree_evaluator::current_user_code (void) const + { + return m_call_stack.current_user_code (); + } + + unwind_protect * tree_evaluator::curr_fcn_unwind_protect_frame (void) + { + return m_call_stack.curr_fcn_unwind_protect_frame (); + } + + octave_user_code * tree_evaluator::debug_user_code (void) const + { + return m_call_stack.debug_user_code (); + } + + octave_function * tree_evaluator::current_function (bool skip_first) const + { + return m_call_stack.current_function (skip_first); + } + + octave_function * tree_evaluator::caller_function (void) const + { + return m_call_stack.current_function (true); + } + + bool tree_evaluator::goto_frame (std::size_t n, bool verbose) + { + return m_call_stack.goto_frame (n, verbose); + } + + void tree_evaluator::goto_caller_frame (void) + { + m_call_stack.goto_caller_frame (); + } + + void tree_evaluator::goto_base_frame (void) + { + m_call_stack.goto_base_frame (); + } + + void tree_evaluator::restore_frame (std::size_t n) + { + return m_call_stack.restore_frame (n); + } + + std::string tree_evaluator::get_dispatch_class (void) const + { + return m_call_stack.get_dispatch_class (); + } + + void tree_evaluator::set_dispatch_class (const std::string& class_name) + { + m_call_stack.set_dispatch_class (class_name); + } + + bool + tree_evaluator::is_class_method_executing (std::string& dclass) const + { + return m_call_stack.is_class_method_executing (dclass); + } + + bool + tree_evaluator::is_class_constructor_executing (std::string& dclass) const + { + return m_call_stack.is_class_constructor_executing (dclass); + } + + std::list> + tree_evaluator::backtrace_frames (octave_idx_type& curr_user_frame) const + { + return m_call_stack.backtrace_frames (curr_user_frame); + } + + std::list> + tree_evaluator::backtrace_frames (void) const + { + return m_call_stack.backtrace_frames (); + } + + std::list + tree_evaluator::backtrace_info (octave_idx_type& curr_user_frame, + bool print_subfn) const + { + return m_call_stack.backtrace_info (curr_user_frame, print_subfn); + } + + std::list tree_evaluator::backtrace_info (void) const + { + return m_call_stack.backtrace_info (); + } + + octave_map + tree_evaluator::backtrace (octave_idx_type& curr_user_frame, + bool print_subfn) const + { + return m_call_stack.backtrace (curr_user_frame, print_subfn); + } + + octave_map tree_evaluator::backtrace (void) const + { + return m_call_stack.backtrace (); + } + + octave_map tree_evaluator::empty_backtrace (void) const + { + return m_call_stack.empty_backtrace (); + } + + std::string tree_evaluator::backtrace_message (void) const + { + std::list frames = backtrace_info (); + + std::ostringstream buf; + + for (const auto& frm : frames) + { + buf << " " << frm.fcn_name (); + + int line = frm.line (); + + if (line > 0) + { + buf << " at line " << line; + + int column = frm.column (); + + if (column > 0) + buf << " column " << column; + + buf << "\n"; + } + } + + return buf.str (); + } + + void tree_evaluator::push_dummy_scope (const std::string& name) + { + symbol_scope dummy_scope (name + "$dummy"); + + m_call_stack.push (dummy_scope); + } + + void tree_evaluator::pop_scope (void) + { + m_call_stack.pop (); + } + + symbol_scope tree_evaluator::get_top_scope (void) const + { + return m_call_stack.top_scope (); + } + + symbol_scope tree_evaluator::get_current_scope (void) const + { + return m_call_stack.current_scope (); + } + + void tree_evaluator::mlock (bool skip_first) const + { + octave_function *fcn = m_call_stack.current_function (skip_first); + + if (! fcn) + error ("mlock: invalid use outside a function"); + + if (fcn->is_builtin_function ()) + { + warning ("mlock: locking built-in function has no effect"); + return; + } + + fcn->lock (); + } + + void tree_evaluator::munlock (bool skip_first) const + { + octave_function *fcn = m_call_stack.current_function (skip_first); + + if (! fcn) + error ("munlock: invalid use outside a function"); + + if (fcn->is_builtin_function ()) + { + warning ("munlock: unlocking built-in function has no effect"); + return; + } + + fcn->unlock (); + } + + bool tree_evaluator::mislocked (bool skip_first) const + { + octave_function *fcn = m_call_stack.current_function (skip_first); + + if (! fcn) + error ("mislocked: invalid use outside a function"); + + return fcn->islocked (); + } + + octave_value + tree_evaluator::max_stack_depth (const octave_value_list& args, int nargout) + { + return m_call_stack.max_stack_depth (args, nargout); + } + + void tree_evaluator::display_call_stack (void) const + { + m_call_stack.display (); + } + + octave_value tree_evaluator::find (const std::string& name) + { + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + octave_value val = frame->varval (name); + + if (val.is_defined ()) + return val; + + // Subfunction. I think it only makes sense to check for + // subfunctions if we are currently executing a function defined + // from a .m file. + + octave_value fcn = frame->find_subfunction (name); + + if (fcn.is_defined ()) + return fcn; + + symbol_table& symtab = m_interpreter.get_symbol_table (); + + return symtab.fcn_table_find (name, ovl ()); + } + + void tree_evaluator::clear_objects (void) + { + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + frame->clear_objects (); + } + + void tree_evaluator::clear_variable (const std::string& name) + { + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + frame->clear_variable (name); + } + + void tree_evaluator::clear_variable_pattern (const std::string& pattern) + { + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + frame->clear_variable_pattern (pattern); + } + + void tree_evaluator::clear_variable_regexp (const std::string& pattern) + { + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + frame->clear_variable_regexp (pattern); + } + + void tree_evaluator::clear_variables (void) + { + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + frame->clear_variables (); + } + + void tree_evaluator::clear_global_variable (const std::string& name) + { + m_call_stack.clear_global_variable (name); + } + + void + tree_evaluator::clear_global_variable_pattern (const std::string& pattern) + { + m_call_stack.clear_global_variable_pattern (pattern); + } + + void tree_evaluator::clear_global_variable_regexp(const std::string& pattern) + { + m_call_stack.clear_global_variable_regexp (pattern); + } + + void tree_evaluator::clear_global_variables (void) + { + m_call_stack.clear_global_variables (); + } + + void tree_evaluator::clear_all (bool force) + { + // FIXME: should this also clear objects? + + clear_variables (); + clear_global_variables (); + + symbol_table& symtab = m_interpreter.get_symbol_table (); + + symtab.clear_functions (force); + } + + void tree_evaluator::clear_symbol (const std::string& name) + { + // FIXME: are we supposed to do both here? + + clear_variable (name); + + symbol_table& symtab = m_interpreter.get_symbol_table (); + + symtab.clear_function (name); + } + + void tree_evaluator::clear_symbol_pattern (const std::string& pattern) + { + // FIXME: are we supposed to do both here? + + clear_variable_pattern (pattern); + + symbol_table& symtab = m_interpreter.get_symbol_table (); + + symtab.clear_function_pattern (pattern); + } + + void tree_evaluator::clear_symbol_regexp (const std::string& pattern) + { + // FIXME: are we supposed to do both here? + + clear_variable_regexp (pattern); + + symbol_table& symtab = m_interpreter.get_symbol_table (); + + symtab.clear_function_regexp (pattern); + } + + std::list tree_evaluator::global_variable_names (void) const + { + return m_call_stack.global_variable_names (); + } + + std::list tree_evaluator::top_level_variable_names (void) const + { + return m_call_stack.top_level_variable_names (); + } + + std::list tree_evaluator::variable_names (void) const + { + return m_call_stack.variable_names (); + } + + // Return a pointer to the user-defined function FNAME. If FNAME is empty, + // search backward for the first user-defined function in the + // current call stack. + + octave_user_code * + tree_evaluator::get_user_code (const std::string& fname, + const std::string& class_name) + { + octave_user_code *user_code = nullptr; + + if (fname.empty ()) + user_code = m_call_stack.debug_user_code (); + else + { + std::string name = fname; + + if (sys::file_ops::dir_sep_char () != '/' && name[0] == '@') + { + auto beg = name.begin () + 2; // never have @/method + auto end = name.end () - 1; // never have trailing '/' + std::replace (beg, end, '/', sys::file_ops::dir_sep_char ()); + } + + std::size_t name_len = name.length (); + + if (name_len > 2 && name.substr (name_len-2) == ".m") + name = name.substr (0, name_len-2); + + if (name.empty ()) + return nullptr; + + symbol_table& symtab = m_interpreter.get_symbol_table (); + + octave_value fcn; + std::size_t p2 = std::string::npos; + + if (name[0] == '@') + { + std::size_t p1 = name.find (sys::file_ops::dir_sep_char (), 1); + + if (p1 == std::string::npos) + return nullptr; + + std::string dispatch_type = name.substr (1, p1-1); + + p2 = name.find ('>', p1); + + std::string method = name.substr (p1+1, p2-1); + + fcn = symtab.find_method (method, dispatch_type); + } + else if (! class_name.empty ()) + { + cdef_manager& cdm = m_interpreter.get_cdef_manager (); + + fcn = cdm.find_method (class_name, name); + + // If there is no classdef method, then try legacy classes. + if (fcn.is_undefined ()) + fcn = symtab.find_method (name, class_name); + } + else + { + p2 = name.find ('>'); + + std::string main_fcn = name.substr (0, p2); + + fcn = symtab.find_function (main_fcn); + } + + // List of function names sub1>sub2>... + std::string subfuns; + + if (p2 != std::string::npos) + subfuns = name.substr (p2+1); + + if (fcn.is_defined () && fcn.is_user_code ()) + user_code = fcn.user_code_value (); + + if (! user_code || subfuns.empty ()) + return user_code; + + fcn = user_code->find_subfunction (subfuns); + + if (fcn.is_undefined ()) + return nullptr; + + user_code = fcn.user_code_value (); + } + + return user_code; + } + + std::string + tree_evaluator::current_function_name (bool skip_first) const + { + octave_function *curfcn = m_call_stack.current_function (skip_first); + + if (curfcn) + return curfcn->name (); + + return ""; + } + + bool + tree_evaluator::in_user_code (void) const + { + return m_call_stack.current_user_code () != nullptr; + } + + void + tree_evaluator::visit_decl_command (tree_decl_command& cmd) + { + if (m_echo_state) + { + int line = cmd.line (); + if (line < 0) + line = 1; + echo_code (line); + m_echo_file_pos = line + 1; + } + + if (m_debug_mode) + do_breakpoint (cmd.is_active_breakpoint (*this)); + + // FIXME: tree_decl_init_list is not derived from tree, so should it + // really have an accept method? + + tree_decl_init_list *init_list = cmd.initializer_list (); + + if (init_list) + init_list->accept (*this); + } + + void + tree_evaluator::visit_decl_elt (tree_decl_elt& elt) + { + tree_identifier *id = elt.ident (); + + if (id) + { + if (elt.is_global ()) + m_call_stack.make_global (id->symbol ()); + else if (elt.is_persistent ()) + m_call_stack.make_persistent (id->symbol ()); + else + error ("declaration list element not global or persistent"); + + octave_lvalue ult = id->lvalue (*this); + + if (ult.is_undefined ()) + { + tree_expression *expr = elt.expression (); + + octave_value init_val; + + if (expr) + init_val = expr->evaluate (*this); + else + init_val = Matrix (); + + ult.assign (octave_value::op_asn_eq, init_val); + } + } + } + + template + void + tree_evaluator::execute_range_loop (const range& rng, int line, + octave_lvalue& ult, + tree_statement_list *loop_body) + { + octave_idx_type steps = rng.numel (); + + if (math::isinf (rng.limit ())) + warning_with_id ("Octave:infinite-loop", + "FOR loop limit is infinite, will stop after %" + OCTAVE_IDX_TYPE_FORMAT " steps", steps); + + for (octave_idx_type i = 0; i < steps; i++) + { + if (m_echo_state) + m_echo_file_pos = line; + + octave_value val (rng.elem (i)); + + ult.assign (octave_value::op_asn_eq, val); + + if (loop_body) + loop_body->accept (*this); + + if (quit_loop_now ()) + break; + } + } + + void + tree_evaluator::visit_simple_for_command (tree_simple_for_command& cmd) + { + int line = cmd.line (); + if (line < 0) + line = 1; + + if (m_echo_state) + { + echo_code (line); + line++; + } + + if (m_debug_mode) + do_breakpoint (cmd.is_active_breakpoint (*this)); + + // FIXME: need to handle PARFOR loops here using cmd.in_parallel () + // and cmd.maxproc_expr (); + + unwind_protect_var upv (m_in_loop_command, true); + + tree_expression *expr = cmd.control_expr (); + + octave_value rhs = expr->evaluate (*this); + + if (rhs.is_undefined ()) + return; + + tree_expression *lhs = cmd.left_hand_side (); + + octave_lvalue ult = lhs->lvalue (*this); + + tree_statement_list *loop_body = cmd.body (); + + if (rhs.is_range ()) + { + // FIXME: is there a better way to dispatch here? + + if (rhs.is_double_type ()) + { + execute_range_loop (rhs.range_value (), line, ult, loop_body); + return; + } + + // For now, disable all but range. + +#if 0 + if (rhs.is_int64_type ()) + { + execute_range_loop (rhs.int64_range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_uint64_type ()) + { + execute_range_loop (rhs.uint64_range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_int32_type ()) + { + execute_range_loop (rhs.int32_range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_uint32_type ()) + { + execute_range_loop (rhs.uint32_range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_int16_type ()) + { + execute_range_loop (rhs.int16_range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_uint16_type ()) + { + execute_range_loop (rhs.uint16_range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_int8_type ()) + { + execute_range_loop (rhs.int8_range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_uint8_type ()) + { + execute_range_loop (rhs.uint8_range_value (), line, ult, loop_body); + return; + } + + if (rhs.is_single_type ()) + { + execute_range_loop (rhs.float_range_value (), line, ult, loop_body); + return; + } +#endif + } + + if (rhs.is_scalar_type ()) + { + if (m_echo_state) + m_echo_file_pos = line; + + ult.assign (octave_value::op_asn_eq, rhs); + + if (loop_body) + loop_body->accept (*this); + + // Maybe decrement break and continue states. + quit_loop_now (); + + return; + } + + // Also handle any range types not explicitly handled above, though + // not as efficiently as the specialized code above. + + if (rhs.is_range () || rhs.is_matrix_type () || rhs.iscell () + || rhs.is_string () || rhs.isstruct ()) + { + // A matrix or cell is reshaped to 2 dimensions and iterated by + // columns. + + dim_vector dv = rhs.dims ().redim (2); + + octave_idx_type nrows = dv(0); + octave_idx_type steps = dv(1); + + octave_value arg = rhs; + if (rhs.ndims () > 2) + arg = arg.reshape (dv); + + if (nrows > 0 && steps > 0) + { + octave_value_list idx; + octave_idx_type iidx; + + // for row vectors, use single index to speed things up. + if (nrows == 1) + { + idx.resize (1); + iidx = 0; + } + else + { + idx.resize (2); + idx(0) = octave_value::magic_colon_t; + iidx = 1; + } + + for (octave_idx_type i = 1; i <= steps; i++) + { + if (m_echo_state) + m_echo_file_pos = line; + + // index_op expects one-based indices. + idx(iidx) = i; + octave_value val = arg.index_op (idx); + + ult.assign (octave_value::op_asn_eq, val); + + if (loop_body) + loop_body->accept (*this); + + if (quit_loop_now ()) + break; + } + } + else + { + // Handle empty cases, while still assigning to loop var. + ult.assign (octave_value::op_asn_eq, arg); + } + + return; + } + + error ("invalid type in for loop expression near line %d, column %d", + cmd.line (), cmd.column ()); + } + + void + tree_evaluator::visit_complex_for_command (tree_complex_for_command& cmd) + { + int line = cmd.line (); + if (line < 0) + line = 1; + + if (m_echo_state) + { + echo_code (line); + line++; + } + + if (m_debug_mode) + do_breakpoint (cmd.is_active_breakpoint (*this)); + + unwind_protect_var upv (m_in_loop_command, true); + + tree_expression *expr = cmd.control_expr (); + + octave_value rhs = expr->evaluate (*this); + + if (rhs.is_undefined ()) + return; + + if (! rhs.isstruct ()) + error ("in statement 'for [X, Y] = VAL', VAL must be a structure"); + + // Cycle through structure elements. First element of id_list + // is set to value and the second is set to the name of the + // structure element. + + tree_argument_list *lhs = cmd.left_hand_side (); + + auto p = lhs->begin (); + + tree_expression *elt = *p++; + + octave_lvalue val_ref = elt->lvalue (*this); + + elt = *p; + + octave_lvalue key_ref = elt->lvalue (*this); + + const octave_map tmp_val = rhs.map_value (); + + tree_statement_list *loop_body = cmd.body (); + + string_vector keys = tmp_val.keys (); + + octave_idx_type nel = keys.numel (); + + for (octave_idx_type i = 0; i < nel; i++) + { + if (m_echo_state) + m_echo_file_pos = line; + + std::string key = keys[i]; + + const Cell val_lst = tmp_val.contents (key); + + octave_idx_type n = val_lst.numel (); + + octave_value val = (n == 1) ? val_lst(0) : octave_value (val_lst); + + val_ref.assign (octave_value::op_asn_eq, val); + key_ref.assign (octave_value::op_asn_eq, key); + + if (loop_body) + loop_body->accept (*this); + + if (quit_loop_now ()) + break; + } + } + + void tree_evaluator::visit_spmd_command (tree_spmd_command& cmd) + { + // For now, we just execute the commands serially. + + tree_statement_list *body = cmd.body (); + + if (body) + body->accept (*this); + } + + octave_value + tree_evaluator::evaluate_anon_fcn_handle (tree_anon_fcn_handle& afh) + { + // FIXME: should CMD_LIST be limited to a single expression? + // I think that is what Matlab does. + + symbol_scope new_scope; + symbol_scope scope = afh.scope (); + if (scope) + new_scope = scope.dup (); + + tree_parameter_list *param_list = afh.parameter_list (); + tree_parameter_list *param_list_dup + = param_list ? param_list->dup (new_scope) : nullptr; + + tree_parameter_list *ret_list = nullptr; + + tree_statement_list *stmt_list = nullptr; + + symbol_scope parent_scope = get_current_scope (); + + new_scope.set_parent (parent_scope); + new_scope.set_primary_parent (parent_scope); + + tree_expression *expr = afh.expression (); + if (expr) + { + tree_expression *expr_dup = expr->dup (new_scope); + tree_statement *stmt = new tree_statement (expr_dup, nullptr); + stmt_list = new tree_statement_list (stmt); + } + + tree_anon_scopes anon_fcn_ctx (afh); + + std::set free_vars = anon_fcn_ctx.free_variables (); + + stack_frame::local_vars_map local_vars; + + std::shared_ptr frame + = m_call_stack.get_current_stack_frame (); + + for (auto& name : free_vars) + { + octave_value val = frame->varval (name); + + if (val.is_defined ()) + local_vars[name] = val; + } + + octave_user_function *af + = new octave_user_function (new_scope, param_list_dup, ret_list, + stmt_list); + + octave_function *curr_fcn = m_call_stack.current_function (); + + bool is_nested = false; + + if (curr_fcn) + { + // FIXME: maybe it would be better to just stash curr_fcn + // instead of individual bits of info about it? + + // An anonymous function defined inside another nested function + // or parent of a nested function also behaves like a nested + // function. + + if (curr_fcn->is_parent_function () || curr_fcn->is_nested_function ()) + { + is_nested = true; + af->mark_as_nested_function (); + new_scope.set_nesting_depth (parent_scope.nesting_depth () + 1); + } + + af->stash_dir_name (curr_fcn->dir_name ()); + + new_scope.cache_fcn_file_name (curr_fcn->fcn_file_name ()); + new_scope.cache_dir_name (curr_fcn->dir_name ()); + + // The following is needed so that class method dispatch works + // properly for anonymous functions that wrap class methods. + + if (curr_fcn->is_class_method () || curr_fcn->is_class_constructor ()) + af->stash_dispatch_class (curr_fcn->dispatch_class ()); + + af->stash_fcn_file_name (curr_fcn->fcn_file_name ()); + } + + af->mark_as_anonymous_function (); + + octave_value ov_fcn (af); + + return (is_nested + ? octave_value (new octave_fcn_handle (ov_fcn, local_vars, frame)) + : octave_value (new octave_fcn_handle (ov_fcn, local_vars))); + } + + octave_value_list + tree_evaluator::execute_builtin_function (octave_builtin& builtin_function, + int nargout, + const octave_value_list& args) + { + octave_value_list retval; + + if (args.has_magic_colon ()) + error ("invalid use of colon in function argument list"); + + profiler::enter block (m_profiler, builtin_function); + + octave_builtin::fcn fcn = builtin_function.function (); + + if (fcn) + retval = (*fcn) (args, nargout); + else + { + octave_builtin::meth meth = builtin_function.method (); + + retval = (*meth) (m_interpreter, args, nargout); + } + + // Do not allow null values to be returned from functions. + // FIXME: perhaps true builtins should be allowed? + + retval.make_storable_values (); + + // Fix the case of a single undefined value. + // This happens when a compiled function uses + // + // octave_value retval; + // + // instead of + // + // octave_value_list retval; + // + // the idiom is very common, so we solve that here. + + if (retval.length () == 1 && retval.xelem (0).is_undefined ()) + retval.clear (); + + return retval; + } + + octave_value_list + tree_evaluator::execute_mex_function (octave_mex_function& mex_function, + int nargout, + const octave_value_list& args) + { + octave_value_list retval; + + if (args.has_magic_colon ()) + error ("invalid use of colon in function argument list"); + + profiler::enter block (m_profiler, mex_function); + + retval = call_mex (mex_function, args, nargout); + + return retval; + } + + octave_value_list + tree_evaluator::execute_user_script (octave_user_script& user_script, + int nargout, + const octave_value_list& args) + { + octave_value_list retval; + + std::string file_name = user_script.fcn_file_name (); + + if (args.length () != 0 || nargout != 0) + error ("invalid call to script %s", file_name.c_str ()); + + tree_statement_list *cmd_list = user_script.body (); + + if (! cmd_list) + return retval; + + // FIXME: Maybe this check belongs in the places where we push a new + // stack frame? Or in the call_stack push method itself? + + if (m_call_stack.size () >= static_cast (m_max_recursion_depth)) + error ("max_recursion_depth exceeded"); + + unwind_protect_var upv (m_statement_context, SC_SCRIPT); + + profiler::enter block (m_profiler, user_script); + + if (echo ()) + push_echo_state (tree_evaluator::ECHO_SCRIPTS, file_name); + + // FIXME: Should we be using tree_evaluator::eval here? + + cmd_list->accept (*this); + + if (m_returning) + m_returning = 0; + + if (m_breaking) + m_breaking--; + + return retval; + } + + void + tree_evaluator::visit_octave_user_script (octave_user_script&) + { + // ?? + panic_impossible (); + } + + octave_value_list + tree_evaluator::execute_user_function (octave_user_function& user_function, + int nargout, + const octave_value_list& xargs) + { + octave_value_list retval; + + // If this function is a classdef constructor, extract the first input + // argument, which must be the partially constructed object instance. + + octave_value_list args (xargs); + octave_value_list ret_args; + + int nargin = args.length (); + + if (user_function.is_classdef_constructor ()) + { + if (nargin > 0) + { + ret_args = args.slice (0, 1, true); + --nargin; + args = args.slice (1, nargin, true); + } + else + panic_impossible (); + } + + // FIXME: this probably shouldn't be a double-precision matrix. + Matrix ignored_outputs = ignored_fcn_outputs (); + + tree_parameter_list *param_list = user_function.parameter_list (); + + bool takes_varargs = false; + int max_inputs = 0; + + if (param_list) + { + takes_varargs = param_list->takes_varargs (); + max_inputs = param_list->length (); + } + + if (! takes_varargs && nargin > max_inputs) + { + std::string name = user_function.name (); + + if (name.empty ()) + name = "@"; + + error_with_id ("Octave:invalid-fun-call", + "%s: function called with too many inputs", + name.c_str ()); + } + + define_parameter_list_from_arg_vector (param_list, args); + + tree_parameter_list *ret_list = user_function.return_list (); + + if (ret_list && ! ret_list->takes_varargs ()) + { + int max_outputs = ret_list->length (); + + if (nargout > max_outputs) + { + std::string name = user_function.name (); + + error_with_id ("Octave:invalid-fun-call", + "%s: function called with too many outputs", + name.c_str ()); + } + } + + bind_auto_fcn_vars (xargs.name_tags (), ignored_outputs, nargin, + nargout, user_function.takes_varargs (), + user_function.all_va_args (args)); + + // For classdef constructor, pre-populate the output arguments + // with the pre-initialized object instance, extracted above. + + if (user_function.is_classdef_constructor ()) + { + if (! ret_list) + error ("%s: invalid classdef constructor, no output argument defined", + user_function.dispatch_class ().c_str ()); + + define_parameter_list_from_arg_vector (ret_list, ret_args); + } + + // FIXME: Maybe this check belongs in the places where we push a + // new stack frame? Or in the call_stack push method itself? + + if (m_call_stack.size () >= static_cast (m_max_recursion_depth)) + error ("max_recursion_depth exceeded"); + + unwind_action act2 ([&user_function] () { + user_function.restore_warning_states (); + }); + + // Evaluate the commands that make up the function. + + unwind_protect_var upv (m_statement_context, SC_FUNCTION); + + tree_statement_list *cmd_list = user_function.body (); + + if (cmd_list) + { + profiler::enter + block (m_profiler, user_function); + + if (echo ()) + push_echo_state (tree_evaluator::ECHO_FUNCTIONS, + user_function.fcn_file_name ()); + + if (user_function.is_special_expr ()) + { + panic_if (cmd_list->length () != 1); + + tree_statement *stmt = cmd_list->front (); + + tree_expression *expr = stmt->expression (); + + if (expr) + { + m_call_stack.set_location (stmt->line (), stmt->column ()); + + retval = expr->evaluate_n (*this, nargout); + } + } + else + cmd_list->accept (*this); + + if (m_returning) + m_returning = 0; + + if (m_breaking) + m_breaking--; + } + + // Copy return values out. + + if (ret_list && ! user_function.is_special_expr ()) + { + Cell varargout; + + if (ret_list->takes_varargs ()) + { + octave_value varargout_varval = varval ("varargout"); + + if (varargout_varval.is_defined ()) + varargout = varargout_varval.xcell_value ("varargout must be a cell array object"); + } + + retval = convert_return_list_to_const_vector (ret_list, nargout, + ignored_outputs, + varargout); + } + + return retval; + } + + void + tree_evaluator::visit_octave_user_function (octave_user_function&) + { + // ?? + panic_impossible (); + } + + void + tree_evaluator::visit_octave_user_function_header (octave_user_function&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_octave_user_function_trailer (octave_user_function&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_function_def (tree_function_def& cmd) + { + octave_value fcn = cmd.function (); + + octave_function *f = fcn.function_value (); + + if (f) + { + std::string nm = f->name (); + + symbol_table& symtab = m_interpreter.get_symbol_table (); + + symtab.install_cmdline_function (nm, fcn); + + // Make sure that any variable with the same name as the new + // function is cleared. + + assign (nm); + } + } + + void + tree_evaluator::visit_identifier (tree_identifier&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_if_clause (tree_if_clause&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_if_command (tree_if_command& cmd) + { + if (m_echo_state) + { + int line = cmd.line (); + if (line < 0) + line = 1; + echo_code (line); + m_echo_file_pos = line + 1; + } + + // FIXME: tree_if_command_list is not derived from tree, so should it + // really have an accept method? + + tree_if_command_list *lst = cmd.cmd_list (); + + if (lst) + lst->accept (*this); + } + + void + tree_evaluator::visit_if_command_list (tree_if_command_list& lst) + { + for (tree_if_clause *tic : lst) + { + tree_expression *expr = tic->condition (); + + if (! (in_debug_repl () + && m_call_stack.current_frame () == m_debug_frame)) + m_call_stack.set_location (tic->line (), tic->column ()); + + if (m_debug_mode && ! tic->is_else_clause ()) + do_breakpoint (tic->is_active_breakpoint (*this)); + + if (tic->is_else_clause () || is_logically_true (expr, "if")) + { + tree_statement_list *stmt_lst = tic->commands (); + + if (stmt_lst) + stmt_lst->accept (*this); + + break; + } + } + } + + void + tree_evaluator::visit_index_expression (tree_index_expression&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_matrix (tree_matrix&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_cell (tree_cell&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_multi_assignment (tree_multi_assignment&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_no_op_command (tree_no_op_command& cmd) + { + if (m_echo_state) + { + int line = cmd.line (); + if (line < 0) + line = 1; + echo_code (line); + m_echo_file_pos = line + 1; + } + + if (m_debug_mode && cmd.is_end_of_fcn_or_script ()) + do_breakpoint (cmd.is_active_breakpoint (*this), true); + } + + void + tree_evaluator::visit_constant (tree_constant&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_fcn_handle (tree_fcn_handle&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_parameter_list (tree_parameter_list&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_postfix_expression (tree_postfix_expression&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_prefix_expression (tree_prefix_expression&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_return_command (tree_return_command& cmd) + { + if (m_echo_state) + { + int line = cmd.line (); + if (line < 0) + line = 1; + echo_code (line); + m_echo_file_pos = line + 1; + } + + if (m_debug_mode) + do_breakpoint (cmd.is_active_breakpoint (*this)); + + // Act like dbcont. + + if (in_debug_repl () && m_call_stack.current_frame () == m_debug_frame) + dbcont (); + else if (m_statement_context == SC_FUNCTION + || m_statement_context == SC_SCRIPT + || m_in_loop_command) + m_returning = 1; + } + + void + tree_evaluator::visit_simple_assignment (tree_simple_assignment&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_statement (tree_statement& stmt) + { + tree_command *cmd = stmt.command (); + tree_expression *expr = stmt.expression (); + + if (cmd || expr) + { + if (! (in_debug_repl () + && m_call_stack.current_frame () == m_debug_frame)) + m_call_stack.set_location (stmt.line (), stmt.column ()); + + try + { + if (cmd) + { + unwind_protect_var *> + upv (m_lvalue_list, nullptr); + + cmd->accept (*this); + } + else + { + if (m_echo_state) + { + int line = stmt.line (); + if (line < 0) + line = 1; + echo_code (line); + m_echo_file_pos = line + 1; + } + + if (m_debug_mode) + do_breakpoint (expr->is_active_breakpoint (*this)); + + // FIXME: maybe all of this should be packaged in + // one virtual function that returns a flag saying whether + // or not the expression will take care of binding ans and + // printing the result. + + // FIXME: it seems that we should just have to + // evaluate the expression and that should take care of + // everything, binding ans as necessary? + + octave_value tmp_result = expr->evaluate (*this, 0); + + if (tmp_result.is_defined ()) + { + bool do_bind_ans = false; + + if (expr->is_identifier ()) + do_bind_ans = ! is_variable (expr); + else + do_bind_ans = ! expr->is_assignment_expression (); + + if (do_bind_ans) + bind_ans (tmp_result, expr->print_result () + && statement_printing_enabled ()); + } + } + } + catch (const std::bad_alloc&) + { + // FIXME: We want to use error_with_id here so that give users + // control over this error message but error_with_id will + // require some memory allocations. Is there anything we can + // do to make those more likely to succeed? + + error_with_id ("Octave:bad-alloc", + "out of memory or dimension too large for Octave's index type"); + } + catch (const interrupt_exception&) + { + // If we are debugging, then continue with next statement. + // Otherwise, jump out of here. + + if (m_debug_mode) + m_interpreter.recover_from_exception (); + else + throw; + } + catch (const execution_exception& ee) + { + error_system& es = m_interpreter.get_error_system (); + + if ((m_interpreter.interactive () + || application::forced_interactive ()) + && ((es.debug_on_error () + && m_bp_table.debug_on_err (es.last_error_id ())) + || (es.debug_on_caught () + && m_bp_table.debug_on_caught (es.last_error_id ()))) + && in_user_code ()) + { + es.save_exception (ee); + es.display_exception (ee); + + enter_debugger (); + + // It doesn't make sense to continue execution after an + // error occurs so force the debugger to quit all debug + // levels and return the the top prompt. + + throw quit_debug_exception (true); + } + else + throw; + } + } + } + + void + tree_evaluator::visit_statement_list (tree_statement_list& lst) + { + // FIXME: commented out along with else clause below. + // static octave_value_list empty_list; + + auto p = lst.begin (); + + if (p != lst.end ()) + { + while (true) + { + tree_statement *elt = *p++; + + if (! elt) + error ("invalid statement found in statement list!"); + + octave_quit (); + + elt->accept (*this); + + if (m_breaking || m_continuing) + break; + + if (m_returning) + break; + + if (p == lst.end ()) + break; + else + { + // Clear previous values before next statement is + // evaluated so that we aren't holding an extra + // reference to a value that may be used next. For + // example, in code like this: + // + // X = rand (N); # refcount for X should be 1 + // # after this statement + // + // X(idx) = val; # no extra copy of X should be + // # needed, but we will be faked + // # out if retval is not cleared + // # between statements here + + // result_values = empty_list; + } + } + } + } + + void + tree_evaluator::visit_switch_case (tree_switch_case&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_switch_case_list (tree_switch_case_list&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_switch_command (tree_switch_command& cmd) + { + if (m_echo_state) + { + int line = cmd.line (); + if (line < 0) + line = 1; + echo_code (line); + m_echo_file_pos = line + 1; + } + + if (m_debug_mode) + do_breakpoint (cmd.is_active_breakpoint (*this)); + + tree_expression *expr = cmd.switch_value (); + + if (! expr) + error ("missing value in switch command near line %d, column %d", + cmd.line (), cmd.column ()); + + octave_value val = expr->evaluate (*this); + + tree_switch_case_list *lst = cmd.case_list (); + + if (lst) + { + for (tree_switch_case *t : *lst) + { + if (t->is_default_case () || switch_case_label_matches (t, val)) + { + tree_statement_list *stmt_lst = t->commands (); + + if (stmt_lst) + stmt_lst->accept (*this); + + break; + } + } + } + } + + void + tree_evaluator::visit_try_catch_command (tree_try_catch_command& cmd) + { + if (m_echo_state) + { + int line = cmd.line (); + if (line < 0) + line = 1; + echo_code (line); + m_echo_file_pos = line + 1; + } + + bool execution_error = false; + octave_scalar_map err_map; + + tree_statement_list *try_code = cmd.body (); + + if (try_code) + { + // unwind frame before catch block + + unwind_protect frame; + + interpreter_try (frame); + + // The catch code is *not* added to unwind_protect stack; it + // doesn't need to be run on interrupts. + + try + { + try_code->accept (*this); + } + catch (const execution_exception& ee) + { + execution_error = true; + + error_system& es = m_interpreter.get_error_system (); + + es.save_exception (ee); + + err_map.assign ("message", es.last_error_message ()); + err_map.assign ("identifier", es.last_error_id ()); + err_map.assign ("stack", es.last_error_stack ()); + + m_interpreter.recover_from_exception (); + } + + // Actions attached to unwind_protect frame will run here, prior + // to executing the catch block. + } + + if (execution_error) + { + tree_statement_list *catch_code = cmd.cleanup (); + + if (catch_code) + { + tree_identifier *expr_id = cmd.identifier (); + + if (expr_id) + { + octave_lvalue ult = expr_id->lvalue (*this); + + ult.assign (octave_value::op_asn_eq, err_map); + } + + // perform actual "catch" block + catch_code->accept (*this); + } + } + } + + void + tree_evaluator::do_unwind_protect_cleanup_code (tree_statement_list *list) + { + unwind_protect frame; + + frame.protect_var (octave_interrupt_state); + octave_interrupt_state = 0; + + // We want to preserve the last location info for possible + // backtracking. + + frame.add (&call_stack::set_line, &m_call_stack, + m_call_stack.current_line ()); + + frame.add (&call_stack::set_column, &m_call_stack, + m_call_stack.current_column ()); + + // Similarly, if we have seen a return or break statement, allow all + // the cleanup code to run before returning or handling the break. + // We don't have to worry about continue statements because they can + // only occur in loops. + + frame.protect_var (m_returning); + m_returning = 0; + + frame.protect_var (m_breaking); + m_breaking = 0; + + try + { + if (list) + list->accept (*this); + } + catch (const execution_exception& ee) + { + error_system& es = m_interpreter.get_error_system (); + + es.save_exception (ee); + m_interpreter.recover_from_exception (); + + if (m_breaking || m_returning) + frame.discard (2); + else + frame.run (2); + + frame.discard (2); + + throw; + } + + // The unwind_protects are popped off the stack in the reverse of + // the order they are pushed on. + + // FIXME: these statements say that if we see a break or + // return statement in the cleanup block, that we want to use the + // new value of the breaking or returning flag instead of restoring + // the previous value. Is that the right thing to do? I think so. + // Consider the case of + // + // function foo () + // unwind_protect + // fprintf (stderr, "1: this should always be executed\n"); + // break; + // fprintf (stderr, "1: this should never be executed\n"); + // unwind_protect_cleanup + // fprintf (stderr, "2: this should always be executed\n"); + // return; + // fprintf (stderr, "2: this should never be executed\n"); + // end_unwind_protect + // endfunction + // + // If we reset the value of the breaking flag, both the returning + // flag and the breaking flag will be set, and we shouldn't have + // both. So, use the most recent one. If there is no return or + // break in the cleanup block, the values should be reset to + // whatever they were when the cleanup block was entered. + + if (m_breaking || m_returning) + frame.discard (2); + else + frame.run (2); + } + + void + tree_evaluator::visit_unwind_protect_command (tree_unwind_protect_command& cmd) + { + if (m_echo_state) + { + int line = cmd.line (); + if (line < 0) + line = 1; + echo_code (line); + m_echo_file_pos = line + 1; + } + + tree_statement_list *cleanup_code = cmd.cleanup (); + + tree_statement_list *unwind_protect_code = cmd.body (); + + if (unwind_protect_code) + { + try + { + unwind_protect_code->accept (*this); + } + catch (const execution_exception& ee) + { + error_system& es = m_interpreter.get_error_system (); + + // FIXME: Maybe we should be able to temporarily set the + // interpreter's exception handling state to something "safe" + // while the cleanup block runs instead of just resetting it + // here? + es.save_exception (ee); + m_interpreter.recover_from_exception (); + + // Run the cleanup code on exceptions, so that it is run even + // in case of interrupt or out-of-memory. + do_unwind_protect_cleanup_code (cleanup_code); + + // If an error occurs inside the cleanup code, a new + // exception will be thrown instead of the original. + throw; + } + catch (const interrupt_exception&) + { + // The comments above apply here as well. + m_interpreter.recover_from_exception (); + do_unwind_protect_cleanup_code (cleanup_code); + throw; + } + + // Also execute the unwind_protect_cleanump code if the + // unwind_protect block runs without error. + do_unwind_protect_cleanup_code (cleanup_code); + } + } + + void + tree_evaluator::visit_while_command (tree_while_command& cmd) + { + int line = cmd.line (); + if (line < 0) + line = 1; + + if (m_echo_state) + { + echo_code (line); + line++; + } + + unwind_protect_var upv (m_in_loop_command, true); + + tree_expression *expr = cmd.condition (); + + if (! expr) + panic_impossible (); + + for (;;) + { + if (m_echo_state) + m_echo_file_pos = line; + + if (m_debug_mode) + do_breakpoint (cmd.is_active_breakpoint (*this)); + + if (is_logically_true (expr, "while")) + { + tree_statement_list *loop_body = cmd.body (); + + if (loop_body) + loop_body->accept (*this); + + if (quit_loop_now ()) + break; + } + else + break; + } + } + + void + tree_evaluator::visit_do_until_command (tree_do_until_command& cmd) + { + int line = cmd.line (); + if (line < 0) + line = 1; + + if (m_echo_state) + { + echo_code (line); + line++; + } + + unwind_protect_var upv (m_in_loop_command, true); + + tree_expression *expr = cmd.condition (); + + if (! expr) + panic_impossible (); + + for (;;) + { + if (m_echo_state) + m_echo_file_pos = line; + + tree_statement_list *loop_body = cmd.body (); + + if (loop_body) + loop_body->accept (*this); + + if (quit_loop_now ()) + break; + + if (m_debug_mode) + do_breakpoint (cmd.is_active_breakpoint (*this)); + + if (is_logically_true (expr, "do-until")) + break; + } + } + + void + tree_evaluator::visit_superclass_ref (tree_superclass_ref&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_metaclass_query (tree_metaclass_query&) + { + panic_impossible (); + } + + void tree_evaluator::bind_ans (const octave_value& val, bool print) + { + static std::string ans = "ans"; + + if (val.is_defined ()) + { + if (val.is_cs_list ()) + { + octave_value_list lst = val.list_value (); + + for (octave_idx_type i = 0; i < lst.length (); i++) + bind_ans (lst(i), print); + } + else + { + // FIXME: Maybe assign could also return the assigned value, + // just for convenience? + + assign (ans, val); + + if (print) + { + // Use varval instead of displaying VAL directly so that + // we get the right type and value for things like + // magic_int values that may mutate when stored. + + octave_value_list args = ovl (varval (ans)); + args.stash_name_tags (string_vector (ans)); + feval ("display", args); + } + } + } + } + + void + tree_evaluator::do_breakpoint (tree_statement& stmt) + { + do_breakpoint (stmt.is_active_breakpoint (*this), + stmt.is_end_of_fcn_or_script ()); + } + + void + tree_evaluator::do_breakpoint (bool is_breakpoint, + bool is_end_of_fcn_or_script) + { + bool break_on_this_statement = false; + + if (is_breakpoint) + break_on_this_statement = true; + else if (m_dbstep_flag > 0) + { + if (m_call_stack.current_frame () == m_debug_frame) + { + if (m_dbstep_flag == 1 || is_end_of_fcn_or_script) + { + // We get here if we are doing a "dbstep" or a "dbstep N" and + // the count has reached 1 so that we must stop and return to + // debug prompt. Alternatively, "dbstep N" has been used but + // the end of the frame has been reached so we stop at the last + // line and return to prompt. + + break_on_this_statement = true; + } + else + { + // Executing "dbstep N". Decrease N by one and continue. + + m_dbstep_flag--; + } + + } + else if (m_dbstep_flag == 1 + && m_call_stack.current_frame () < m_debug_frame) + { + // We stepped out from the end of a function. + + m_debug_frame = m_call_stack.current_frame (); + + break_on_this_statement = true; + } + } + else if (m_dbstep_flag == -1) + { + // We get here if we are doing a "dbstep in". + + break_on_this_statement = true; + + m_debug_frame = m_call_stack.current_frame (); + } + else if (m_dbstep_flag == -2) + { + // We get here if we are doing a "dbstep out". Check for end of + // function and whether the current frame is the same as the + // cached value because we want to step out from the frame where + // "dbstep out" was evaluated, not from any functions called from + // that frame. + + if (is_end_of_fcn_or_script + && m_call_stack.current_frame () == m_debug_frame) + m_dbstep_flag = -1; + } + + if (! break_on_this_statement) + break_on_this_statement = m_break_on_next_stmt; + + m_break_on_next_stmt = false; + + if (break_on_this_statement) + { + m_dbstep_flag = 0; + + enter_debugger (); + } + } + + bool + tree_evaluator::is_logically_true (tree_expression *expr, + const char *warn_for) + { + bool expr_value = false; + + m_call_stack.set_location (expr->line (), expr->column ()); + + octave_value t1 = expr->evaluate (*this); + + if (t1.is_defined ()) + return t1.is_true (); + else + error ("%s: undefined value used in conditional expression", warn_for); + + return expr_value; + } + + octave_value + tree_evaluator::max_recursion_depth (const octave_value_list& args, + int nargout) + { + return set_internal_variable (m_max_recursion_depth, args, nargout, + "max_recursion_depth", 0); + } + + symbol_info_list + tree_evaluator::glob_symbol_info (const std::string& pattern) const + { + return m_call_stack.glob_symbol_info (pattern); + } + + symbol_info_list + tree_evaluator::regexp_symbol_info (const std::string& pattern) const + { + return m_call_stack.regexp_symbol_info (pattern); + } + + symbol_info_list + tree_evaluator::get_symbol_info (void) + { + return m_call_stack.get_symbol_info (); + } + + symbol_info_list + tree_evaluator::top_scope_symbol_info (void) const + { + return m_call_stack.top_scope_symbol_info (); + } + + octave_map tree_evaluator::get_autoload_map (void) const + { + Cell fcn_names (dim_vector (m_autoload_map.size (), 1)); + Cell file_names (dim_vector (m_autoload_map.size (), 1)); + + octave_idx_type i = 0; + for (const auto& fcn_fname : m_autoload_map) + { + fcn_names(i) = fcn_fname.first; + file_names(i) = fcn_fname.second; + + i++; + } + + octave_map m; + + m.assign ("function", fcn_names); + m.assign ("file", file_names); + + return m; + } + + std::string tree_evaluator::lookup_autoload (const std::string& nm) const + { + std::string retval; + + auto p = m_autoload_map.find (nm); + + if (p != m_autoload_map.end ()) + { + load_path& lp = m_interpreter.get_load_path (); + + retval = lp.find_file (p->second); + } + + return retval; + } + + std::list tree_evaluator::autoloaded_functions (void) const + { + std::list names; + + for (const auto& fcn_fname : m_autoload_map) + names.push_back (fcn_fname.first); + + return names; + } + + std::list + tree_evaluator::reverse_lookup_autoload (const std::string& nm) const + { + std::list names; + + for (const auto& fcn_fname : m_autoload_map) + if (nm == fcn_fname.second) + names.push_back (fcn_fname.first); + + return names; + } + + void tree_evaluator::add_autoload (const std::string& fcn, + const std::string& nm) + { + std::string file_name = check_autoload_file (nm); + + m_autoload_map[fcn] = file_name; + } + + void tree_evaluator::remove_autoload (const std::string& fcn, + const std::string& nm) + { + check_autoload_file (nm); + + // Remove function from symbol table and autoload map. + symbol_table& symtab = m_interpreter.get_symbol_table (); + + symtab.clear_dld_function (fcn); + + m_autoload_map.erase (fcn); + } + + octave_value + tree_evaluator::whos_line_format (const octave_value_list& args, int nargout) + { + return set_internal_variable (m_whos_line_format, args, nargout, + "whos_line_format"); + } + + octave_value + tree_evaluator::silent_functions (const octave_value_list& args, int nargout) + { + return set_internal_variable (m_silent_functions, args, nargout, + "silent_functions"); + } + + octave_value + tree_evaluator::string_fill_char (const octave_value_list& args, int nargout) + { + return set_internal_variable (m_string_fill_char, args, nargout, + "string_fill_char"); + } + + // Final step of processing an indexing error. Add the name of the + // variable being indexed, if any, then issue an error. (Will this also + // be needed by pt-lvalue, which calls subsref?) + + void tree_evaluator::final_index_error (index_exception& ie, + const tree_expression *expr) + { + std::string extra_message; + + if (is_variable (expr)) + { + std::string var = expr->name (); + + ie.set_var (var); + + symbol_table& symtab = m_interpreter.get_symbol_table (); + + octave_value fcn = symtab.find_function (var); + + if (fcn.is_function ()) + { + octave_function *fp = fcn.function_value (); + + if (fp && fp->name () == var) + extra_message + = " (note: variable '" + var + "' shadows function)"; + } + } + + std::string msg = ie.message () + extra_message; + + error_with_id (ie.err_id (), "%s", msg.c_str ()); + } + + octave_value + tree_evaluator::do_who (int argc, const string_vector& argv, + bool return_list, bool verbose) + { + return m_call_stack.do_who (argc, argv, return_list, verbose); + } + + octave_value_list + tree_evaluator::make_value_list (tree_argument_list *args, + const string_vector& arg_nm) + { + octave_value_list retval; + + if (args) + { + unwind_protect_var *> + upv (m_lvalue_list, nullptr); + + int len = args->length (); + + unwind_protect_var upv2 (m_index_position); + unwind_protect_var upv3 (m_num_indices); + + m_num_indices = len; + + std::list arg_vals; + + int k = 0; + + for (auto elt : *args) + { + // FIXME: is it possible for elt to be invalid? + + if (! elt) + break; + + m_index_position = k++; + + octave_value tmp = elt->evaluate (*this); + + if (tmp.is_cs_list ()) + { + octave_value_list tmp_ovl = tmp.list_value (); + + for (octave_idx_type i = 0; i < tmp_ovl.length (); i++) + arg_vals.push_back (tmp_ovl(i)); + } + else if (tmp.is_defined ()) + arg_vals.push_back (tmp); + } + + retval = octave_value_list (arg_vals); + } + + octave_idx_type n = retval.length (); + + if (n > 0) + retval.stash_name_tags (arg_nm); + + return retval; + } + + std::list + tree_evaluator::make_lvalue_list (tree_argument_list *lhs) + { + std::list retval; + + for (tree_expression *elt : *lhs) + retval.push_back (elt->lvalue (*this)); + + return retval; + } + + void + tree_evaluator::push_echo_state (int type, const std::string& file_name, + int pos) + { + unwind_protect *frame = m_call_stack.curr_fcn_unwind_protect_frame (); + + if (frame) + { + push_echo_state_cleanup (*frame); + + set_echo_state (type, file_name, pos); + } + } + + void + tree_evaluator::set_echo_state (int type, const std::string& file_name, + int pos) + { + m_echo_state = echo_this_file (file_name, type); + m_echo_file_name = file_name; + m_echo_file_pos = pos; + } + + void + tree_evaluator::uwp_set_echo_state (bool state, const std::string& file_name, + int pos) + { + m_echo_state = state; + m_echo_file_name = file_name; + m_echo_file_pos = pos; + } + + void + tree_evaluator::maybe_set_echo_state (void) + { + octave_function *caller = caller_function (); + + if (caller && caller->is_user_code ()) + { + octave_user_code *fcn = dynamic_cast (caller); + + int type = fcn->is_user_function () ? ECHO_FUNCTIONS : ECHO_SCRIPTS; + + std::string file_name = fcn->fcn_file_name (); + + // We want the line where "echo" was called, not the line number + // stored in the stack frame that was created for the echo + // function (that will always be -1). + + int pos = m_call_stack.current_user_code_line (); + + if (pos < 0) + pos = 1; + + set_echo_state (type, file_name, pos); + } + } + + void + tree_evaluator::push_echo_state_cleanup (unwind_protect& frame) + { + frame.add (&tree_evaluator::uwp_set_echo_state, this, + m_echo_state, m_echo_file_name, m_echo_file_pos); + } + + bool tree_evaluator::maybe_push_echo_state_cleanup (void) + { + // This function is expected to be called from ECHO, which would be + // the top of the call stack. If the caller of ECHO is a + // user-defined function or script, then set up unwind-protect + // elements to restore echo state. + + unwind_protect *frame = m_call_stack.curr_fcn_unwind_protect_frame (); + + if (frame) + { + push_echo_state_cleanup (*frame); + return true; + } + + return false; + } + + + octave_value + tree_evaluator::echo (const octave_value_list& args, int) + { + bool cleanup_pushed = maybe_push_echo_state_cleanup (); + + string_vector argv = args.make_argv (); + + switch (args.length ()) + { + case 0: + if ((m_echo & ECHO_SCRIPTS) || (m_echo & ECHO_FUNCTIONS)) + { + m_echo = ECHO_OFF; + m_echo_files.clear (); + } + else + m_echo = ECHO_SCRIPTS; break; - octave_value tmp = elt->evaluate (*this); - - if (tmp.is_cs_list ()) + case 1: { - octave_value_list tmp_ovl = tmp.list_value (); - - for (octave_idx_type i = 0; i < tmp_ovl.length (); i++) - arg_vals.push_back (tmp_ovl(i)); - } - else if (tmp.is_defined ()) - arg_vals.push_back (tmp); - } - - return octave_value_list (arg_vals); -} - -octave_value_list -tree_evaluator::convert_return_list_to_const_vector -(tree_parameter_list *ret_list, int nargout, const Matrix& ignored_outputs, - const Cell& varargout) -{ - octave_idx_type vlen = varargout.numel (); - int len = ret_list->length (); - - // Special case. Will do a shallow copy. - if (len == 0) - return varargout; - else - { - int i = 0; - int k = 0; - int num_ignored = ignored_outputs.numel (); - int ignored = num_ignored > 0 ? ignored_outputs(k) - 1 : -1; - - if (nargout <= len) - { - int nout = nargout > 0 ? nargout : 1; - octave_value_list retval (nout); - - for (tree_decl_elt *elt : *ret_list) + std::string arg0 = argv[0]; + + if (arg0 == "on") + m_echo = ECHO_SCRIPTS; + else if (arg0 == "off") + m_echo = ECHO_OFF; + else { - if (nargout == 0 && ! is_defined (elt->ident ())) - break; - - if (ignored >= 0 && i == ignored) + std::string file = fcn_file_in_path (arg0); + file = sys::env::make_absolute (file); + + if (file.empty ()) + error ("echo: no such file %s", arg0.c_str ()); + + if (m_echo & ECHO_ALL) { - i++; - k++; - ignored = k < num_ignored ? ignored_outputs(k) - 1 : -1; + // Echo is enabled for all functions, so turn it off + // for this one. + + m_echo_files[file] = false; } else - retval(i++) = evaluate (elt); - - if (i == nout) - break; - } - - return retval; - } - else - { - octave_value_list retval (len + vlen); - - for (tree_decl_elt *elt : *ret_list) - { - if (ignored >= 0 && i == ignored) { - i++; - k++; - ignored = k < num_ignored ? ignored_outputs(k) - 1 : -1; - } - else - retval(i++) = evaluate (elt); - } - - for (octave_idx_type j = 0; j < vlen; j++) - retval(i++) = varargout(j); - - return retval; - } - } -} - -bool -tree_evaluator::eval_decl_elt (tree_decl_elt *elt) -{ - bool retval = false; - - tree_identifier *id = elt->ident (); - tree_expression *expr = elt->expression (); - - if (id && expr) - { - octave_lvalue ult = id->lvalue (*this); - - octave_value init_val = expr->evaluate (*this); - - ult.assign (octave_value::op_asn_eq, init_val); - - retval = true; - } - - return retval; -} - -bool -tree_evaluator::switch_case_label_matches (tree_switch_case *expr, - const octave_value& val) -{ - tree_expression *label = expr->case_label (); - - octave_value label_value = label->evaluate (*this); - - if (label_value.is_defined ()) - { - if (label_value.iscell ()) - { - Cell cell (label_value.cell_value ()); - - for (octave_idx_type i = 0; i < cell.rows (); i++) - { - for (octave_idx_type j = 0; j < cell.columns (); j++) - { - bool match = val.is_equal (cell(i, j)); - - if (match) - return true; + // Echo may be enabled for specific functions. + + auto p = m_echo_files.find (file); + + if (p == m_echo_files.end ()) + { + // Not this one, so enable it. + + m_echo |= ECHO_FUNCTIONS; + m_echo_files[file] = true; + } + else + { + // This one is already in the list. Flip the + // status for it. + + p->second = ! p->second; + } } } } - else - return val.is_equal (label_value); - } - - return false; -} - -void tree_evaluator::push_stack_frame (const symbol_scope& scope) -{ - m_call_stack.push (scope); -} - -void tree_evaluator::push_stack_frame (octave_user_function *fcn, - const std::shared_ptr& closure_frames) -{ - m_call_stack.push (fcn, closure_frames); -} - -void tree_evaluator::push_stack_frame (octave_user_function *fcn, - const stack_frame::local_vars_map& local_vars, - const std::shared_ptr& closure_frames) -{ - m_call_stack.push (fcn, local_vars, closure_frames); -} - -void tree_evaluator::push_stack_frame (octave_user_script *script) -{ - m_call_stack.push (script); -} - -void tree_evaluator::push_stack_frame (octave_function *fcn) -{ - m_call_stack.push (fcn); -} - -void tree_evaluator::pop_stack_frame (void) -{ - m_call_stack.pop (); -} - -int tree_evaluator::current_line (void) const -{ - return m_call_stack.current_line (); -} - -int tree_evaluator::current_column (void) const -{ - return m_call_stack.current_column (); -} - -int tree_evaluator::debug_user_code_line (void) const -{ - return m_call_stack.debug_user_code_line (); -} - -int tree_evaluator::debug_user_code_column (void) const -{ - return m_call_stack.debug_user_code_column (); -} - -void tree_evaluator::debug_where (std::ostream& os) const -{ - std::shared_ptr frm = m_call_stack.current_user_frame (); - - frm->display_stopped_in_message (os); -} - -octave_user_code *tree_evaluator::current_user_code (void) const -{ - return m_call_stack.current_user_code (); -} - -unwind_protect *tree_evaluator::curr_fcn_unwind_protect_frame (void) -{ - return m_call_stack.curr_fcn_unwind_protect_frame (); -} - -octave_user_code *tree_evaluator::debug_user_code (void) const -{ - return m_call_stack.debug_user_code (); -} - -octave_function *tree_evaluator::current_function (bool skip_first) const -{ - return m_call_stack.current_function (skip_first); -} - -octave_function *tree_evaluator::caller_function (void) const -{ - return m_call_stack.current_function (true); -} - -bool tree_evaluator::goto_frame (std::size_t n, bool verbose) -{ - return m_call_stack.goto_frame (n, verbose); -} - -void tree_evaluator::goto_caller_frame (void) -{ - m_call_stack.goto_caller_frame (); -} - -void tree_evaluator::goto_base_frame (void) -{ - m_call_stack.goto_base_frame (); -} - -void tree_evaluator::restore_frame (std::size_t n) -{ - return m_call_stack.restore_frame (n); -} - -std::string tree_evaluator::get_dispatch_class (void) const -{ - return m_call_stack.get_dispatch_class (); -} - -void tree_evaluator::set_dispatch_class (const std::string& class_name) -{ - m_call_stack.set_dispatch_class (class_name); -} - -bool -tree_evaluator::is_class_method_executing (std::string& dclass) const -{ - return m_call_stack.is_class_method_executing (dclass); -} - -bool -tree_evaluator::is_class_constructor_executing (std::string& dclass) const -{ - return m_call_stack.is_class_constructor_executing (dclass); -} - -std::list> - tree_evaluator::backtrace_frames (octave_idx_type& curr_user_frame) const -{ - return m_call_stack.backtrace_frames (curr_user_frame); -} - -std::list> - tree_evaluator::backtrace_frames (void) const -{ - return m_call_stack.backtrace_frames (); -} - -std::list -tree_evaluator::backtrace_info (octave_idx_type& curr_user_frame, - bool print_subfn) const -{ - return m_call_stack.backtrace_info (curr_user_frame, print_subfn); -} - -std::list tree_evaluator::backtrace_info (void) const -{ - return m_call_stack.backtrace_info (); -} - -octave_map -tree_evaluator::backtrace (octave_idx_type& curr_user_frame, - bool print_subfn) const -{ - return m_call_stack.backtrace (curr_user_frame, print_subfn); -} - -octave_map tree_evaluator::backtrace (void) const -{ - return m_call_stack.backtrace (); -} - -octave_map tree_evaluator::empty_backtrace (void) const -{ - return m_call_stack.empty_backtrace (); -} - -std::string tree_evaluator::backtrace_message (void) const -{ - std::list frames = backtrace_info (); - - std::ostringstream buf; - - for (const auto& frm : frames) - { - buf << " " << frm.fcn_name (); - - int line = frm.line (); - - if (line > 0) + break; + + case 2: { - buf << " at line " << line; - - int column = frm.column (); - - if (column > 0) - buf << " column " << column; - - buf << "\n"; - } - } - - return buf.str (); -} - -void tree_evaluator::push_dummy_scope (const std::string& name) -{ - symbol_scope dummy_scope (name + "$dummy"); - - m_call_stack.push (dummy_scope); -} - -void tree_evaluator::pop_scope (void) -{ - m_call_stack.pop (); -} - -symbol_scope tree_evaluator::get_top_scope (void) const -{ - return m_call_stack.top_scope (); -} - -symbol_scope tree_evaluator::get_current_scope (void) const -{ - return m_call_stack.current_scope (); -} - -void tree_evaluator::mlock (bool skip_first) const -{ - octave_function *fcn = m_call_stack.current_function (skip_first); - - if (! fcn) - error ("mlock: invalid use outside a function"); - - if (fcn->is_builtin_function ()) - { - warning ("mlock: locking built-in function has no effect"); - return; - } - - fcn->lock (); -} - -void tree_evaluator::munlock (bool skip_first) const -{ - octave_function *fcn = m_call_stack.current_function (skip_first); - - if (! fcn) - error ("munlock: invalid use outside a function"); - - if (fcn->is_builtin_function ()) - { - warning ("munlock: unlocking built-in function has no effect"); - return; - } - - fcn->unlock (); -} - -bool tree_evaluator::mislocked (bool skip_first) const -{ - octave_function *fcn = m_call_stack.current_function (skip_first); - - if (! fcn) - error ("mislocked: invalid use outside a function"); - - return fcn->islocked (); -} - -octave_value -tree_evaluator::max_stack_depth (const octave_value_list& args, int nargout) -{ - return m_call_stack.max_stack_depth (args, nargout); -} - -void tree_evaluator::display_call_stack (void) const -{ - m_call_stack.display (); -} - -octave_value tree_evaluator::find (const std::string& name) -{ - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - octave_value val = frame->varval (name); - - if (val.is_defined ()) - return val; - - // Subfunction. I think it only makes sense to check for - // subfunctions if we are currently executing a function defined - // from a .m file. - - octave_value fcn = frame->find_subfunction (name); - - if (fcn.is_defined ()) - return fcn; - - symbol_table& symtab = m_interpreter.get_symbol_table (); - - return symtab.fcn_table_find (name, ovl ()); -} - -void tree_evaluator::clear_objects (void) -{ - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - frame->clear_objects (); -} - -void tree_evaluator::clear_variable (const std::string& name) -{ - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - frame->clear_variable (name); -} - -void tree_evaluator::clear_variable_pattern (const std::string& pattern) -{ - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - frame->clear_variable_pattern (pattern); -} - -void tree_evaluator::clear_variable_regexp (const std::string& pattern) -{ - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - frame->clear_variable_regexp (pattern); -} - -void tree_evaluator::clear_variables (void) -{ - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - frame->clear_variables (); -} - -void tree_evaluator::clear_global_variable (const std::string& name) -{ - m_call_stack.clear_global_variable (name); -} - -void -tree_evaluator::clear_global_variable_pattern (const std::string& pattern) -{ - m_call_stack.clear_global_variable_pattern (pattern); -} - -void tree_evaluator::clear_global_variable_regexp(const std::string& pattern) -{ - m_call_stack.clear_global_variable_regexp (pattern); -} - -void tree_evaluator::clear_global_variables (void) -{ - m_call_stack.clear_global_variables (); -} - -void tree_evaluator::clear_all (bool force) -{ - // FIXME: should this also clear objects? - - clear_variables (); - clear_global_variables (); - - symbol_table& symtab = m_interpreter.get_symbol_table (); - - symtab.clear_functions (force); -} - -void tree_evaluator::clear_symbol (const std::string& name) -{ - // FIXME: are we supposed to do both here? - - clear_variable (name); - - symbol_table& symtab = m_interpreter.get_symbol_table (); - - symtab.clear_function (name); -} - -void tree_evaluator::clear_symbol_pattern (const std::string& pattern) -{ - // FIXME: are we supposed to do both here? - - clear_variable_pattern (pattern); - - symbol_table& symtab = m_interpreter.get_symbol_table (); - - symtab.clear_function_pattern (pattern); -} - -void tree_evaluator::clear_symbol_regexp (const std::string& pattern) -{ - // FIXME: are we supposed to do both here? - - clear_variable_regexp (pattern); - - symbol_table& symtab = m_interpreter.get_symbol_table (); - - symtab.clear_function_regexp (pattern); -} - -std::list tree_evaluator::global_variable_names (void) const -{ - return m_call_stack.global_variable_names (); -} - -std::list tree_evaluator::top_level_variable_names (void) const -{ - return m_call_stack.top_level_variable_names (); -} - -std::list tree_evaluator::variable_names (void) const -{ - return m_call_stack.variable_names (); -} - -// Return a pointer to the user-defined function FNAME. If FNAME is empty, -// search backward for the first user-defined function in the -// current call stack. - -octave_user_code * -tree_evaluator::get_user_code (const std::string& fname, - const std::string& class_name) -{ - octave_user_code *user_code = nullptr; - - if (fname.empty ()) - user_code = m_call_stack.debug_user_code (); - else - { - std::string name = fname; - - if (sys::file_ops::dir_sep_char () != '/' && name[0] == '@') - { - auto beg = name.begin () + 2; // never have @/method - auto end = name.end () - 1; // never have trailing '/' - std::replace (beg, end, '/', sys::file_ops::dir_sep_char ()); - } - - std::size_t name_len = name.length (); - - if (name_len > 2 && name.substr (name_len-2) == ".m") - name = name.substr (0, name_len-2); - - if (name.empty ()) - return nullptr; - - symbol_table& symtab = m_interpreter.get_symbol_table (); - - octave_value fcn; - std::size_t p2 = std::string::npos; - - if (name[0] == '@') - { - std::size_t p1 = name.find (sys::file_ops::dir_sep_char (), 1); - - if (p1 == std::string::npos) - return nullptr; - - std::string dispatch_type = name.substr (1, p1-1); - - p2 = name.find ('>', p1); - - std::string method = name.substr (p1+1, p2-1); - - fcn = symtab.find_method (method, dispatch_type); - } - else if (! class_name.empty ()) - { - cdef_manager& cdm = m_interpreter.get_cdef_manager (); - - fcn = cdm.find_method (class_name, name); - - // If there is no classdef method, then try legacy classes. - if (fcn.is_undefined ()) - fcn = symtab.find_method (name, class_name); - } - else - { - p2 = name.find ('>'); - - std::string main_fcn = name.substr (0, p2); - - fcn = symtab.find_function (main_fcn); - } - - // List of function names sub1>sub2>... - std::string subfuns; - - if (p2 != std::string::npos) - subfuns = name.substr (p2+1); - - if (fcn.is_defined () && fcn.is_user_code ()) - user_code = fcn.user_code_value (); - - if (! user_code || subfuns.empty ()) - return user_code; - - fcn = user_code->find_subfunction (subfuns); - - if (fcn.is_undefined ()) - return nullptr; - - user_code = fcn.user_code_value (); - } - - return user_code; -} - -std::string -tree_evaluator::current_function_name (bool skip_first) const -{ - octave_function *curfcn = m_call_stack.current_function (skip_first); - - if (curfcn) - return curfcn->name (); - - return ""; -} - -bool -tree_evaluator::in_user_code (void) const -{ - return m_call_stack.current_user_code () != nullptr; -} - -void -tree_evaluator::visit_decl_command (tree_decl_command& cmd) -{ - if (m_echo_state) - { - int line = cmd.line (); - if (line < 0) - line = 1; - echo_code (line); - m_echo_file_pos = line + 1; - } - - if (m_debug_mode) - do_breakpoint (cmd.is_active_breakpoint (*this)); - - // FIXME: tree_decl_init_list is not derived from tree, so should it - // really have an accept method? - - tree_decl_init_list *init_list = cmd.initializer_list (); - - if (init_list) - init_list->accept (*this); -} - -void -tree_evaluator::visit_decl_elt (tree_decl_elt& elt) -{ - tree_identifier *id = elt.ident (); - - if (id) - { - if (elt.is_global ()) - m_call_stack.make_global (id->symbol ()); - else if (elt.is_persistent ()) - m_call_stack.make_persistent (id->symbol ()); - else - error ("declaration list element not global or persistent"); - - octave_lvalue ult = id->lvalue (*this); - - if (ult.is_undefined ()) - { - tree_expression *expr = elt.expression (); - - octave_value init_val; - - if (expr) - init_val = expr->evaluate (*this); - else - init_val = Matrix (); - - ult.assign (octave_value::op_asn_eq, init_val); - } - } -} - -template -void -tree_evaluator::execute_range_loop (const range& rng, int line, - octave_lvalue& ult, - tree_statement_list *loop_body) -{ - octave_idx_type steps = rng.numel (); - - if (math::isinf (rng.limit ())) - warning_with_id ("Octave:infinite-loop", - "FOR loop limit is infinite, will stop after %" - OCTAVE_IDX_TYPE_FORMAT " steps", steps); - - for (octave_idx_type i = 0; i < steps; i++) - { - if (m_echo_state) - m_echo_file_pos = line; - - octave_value val (rng.elem (i)); - - ult.assign (octave_value::op_asn_eq, val); - - if (loop_body) - loop_body->accept (*this); - - if (quit_loop_now ()) - break; - } -} - -void -tree_evaluator::visit_simple_for_command (tree_simple_for_command& cmd) -{ - int line = cmd.line (); - if (line < 0) - line = 1; - - if (m_echo_state) - { - echo_code (line); - line++; - } - - if (m_debug_mode) - do_breakpoint (cmd.is_active_breakpoint (*this)); - - // FIXME: need to handle PARFOR loops here using cmd.in_parallel () - // and cmd.maxproc_expr (); - - unwind_protect_var upv (m_in_loop_command, true); - - tree_expression *expr = cmd.control_expr (); - - octave_value rhs = expr->evaluate (*this); - - if (rhs.is_undefined ()) - return; - - tree_expression *lhs = cmd.left_hand_side (); - - octave_lvalue ult = lhs->lvalue (*this); - - tree_statement_list *loop_body = cmd.body (); - - if (rhs.is_range ()) - { - // FIXME: is there a better way to dispatch here? - - if (rhs.is_double_type ()) - { - execute_range_loop (rhs.range_value (), line, ult, loop_body); - return; - } - - // For now, disable all but range. - -#if 0 - if (rhs.is_int64_type ()) - { - execute_range_loop (rhs.int64_range_value (), line, ult, loop_body); - return; - } - - if (rhs.is_uint64_type ()) - { - execute_range_loop (rhs.uint64_range_value (), line, ult, loop_body); - return; - } - - if (rhs.is_int32_type ()) - { - execute_range_loop (rhs.int32_range_value (), line, ult, loop_body); - return; - } - - if (rhs.is_uint32_type ()) - { - execute_range_loop (rhs.uint32_range_value (), line, ult, loop_body); - return; - } - - if (rhs.is_int16_type ()) - { - execute_range_loop (rhs.int16_range_value (), line, ult, loop_body); - return; - } - - if (rhs.is_uint16_type ()) - { - execute_range_loop (rhs.uint16_range_value (), line, ult, loop_body); - return; - } - - if (rhs.is_int8_type ()) - { - execute_range_loop (rhs.int8_range_value (), line, ult, loop_body); - return; - } - - if (rhs.is_uint8_type ()) - { - execute_range_loop (rhs.uint8_range_value (), line, ult, loop_body); - return; - } - - if (rhs.is_single_type ()) - { - execute_range_loop (rhs.float_range_value (), line, ult, loop_body); - return; - } -#endif - } - - if (rhs.is_scalar_type ()) - { - if (m_echo_state) - m_echo_file_pos = line; - - ult.assign (octave_value::op_asn_eq, rhs); - - if (loop_body) - loop_body->accept (*this); - - // Maybe decrement break and continue states. - quit_loop_now (); - - return; - } - - // Also handle any range types not explicitly handled above, though - // not as efficiently as the specialized code above. - - if (rhs.is_range () || rhs.is_matrix_type () || rhs.iscell () - || rhs.is_string () || rhs.isstruct ()) - { - // A matrix or cell is reshaped to 2 dimensions and iterated by - // columns. - - dim_vector dv = rhs.dims ().redim (2); - - octave_idx_type nrows = dv(0); - octave_idx_type steps = dv(1); - - octave_value arg = rhs; - if (rhs.ndims () > 2) - arg = arg.reshape (dv); - - if (nrows > 0 && steps > 0) - { - octave_value_list idx; - octave_idx_type iidx; - - // for row vectors, use single index to speed things up. - if (nrows == 1) + std::string arg0 = argv[0]; + std::string arg1 = argv[1]; + + if (arg1 == "on" || arg1 == "off") + std::swap (arg0, arg1); + + if (arg0 == "on") { - idx.resize (1); - iidx = 0; + if (arg1 == "all") + { + m_echo = (ECHO_SCRIPTS | ECHO_FUNCTIONS | ECHO_ALL); + m_echo_files.clear (); + } + else + { + std::string file = fcn_file_in_path (arg1); + file = sys::env::make_absolute (file); + + if (file.empty ()) + error ("echo: no such file %s", arg1.c_str ()); + + m_echo |= ECHO_FUNCTIONS; + m_echo_files[file] = true; + } + } + else if (arg0 == "off") + { + if (arg1 == "all") + { + m_echo = ECHO_OFF; + m_echo_files.clear (); + } + else + { + std::string file = fcn_file_in_path (arg1); + file = sys::env::make_absolute (file); + + if (file.empty ()) + error ("echo: no such file %s", arg1.c_str ()); + + m_echo_files[file] = false; + } } else - { - idx.resize (2); - idx(0) = octave_value::magic_colon_t; - iidx = 1; - } - - for (octave_idx_type i = 1; i <= steps; i++) - { - if (m_echo_state) - m_echo_file_pos = line; - - // index_op expects one-based indices. - idx(iidx) = i; - octave_value val = arg.index_op (idx); - - ult.assign (octave_value::op_asn_eq, val); - - if (loop_body) - loop_body->accept (*this); - - if (quit_loop_now ()) - break; - } - } - else - { - // Handle empty cases, while still assigning to loop var. - ult.assign (octave_value::op_asn_eq, arg); - } - - return; - } - - error ("invalid type in for loop expression near line %d, column %d", - cmd.line (), cmd.column ()); -} - -void -tree_evaluator::visit_complex_for_command (tree_complex_for_command& cmd) -{ - int line = cmd.line (); - if (line < 0) - line = 1; - - if (m_echo_state) - { - echo_code (line); - line++; - } - - if (m_debug_mode) - do_breakpoint (cmd.is_active_breakpoint (*this)); - - unwind_protect_var upv (m_in_loop_command, true); - - tree_expression *expr = cmd.control_expr (); - - octave_value rhs = expr->evaluate (*this); - - if (rhs.is_undefined ()) - return; - - if (! rhs.isstruct ()) - error ("in statement 'for [X, Y] = VAL', VAL must be a structure"); - - // Cycle through structure elements. First element of id_list - // is set to value and the second is set to the name of the - // structure element. - - tree_argument_list *lhs = cmd.left_hand_side (); - - auto p = lhs->begin (); - - tree_expression *elt = *p++; - - octave_lvalue val_ref = elt->lvalue (*this); - - elt = *p; - - octave_lvalue key_ref = elt->lvalue (*this); - - const octave_map tmp_val = rhs.map_value (); - - tree_statement_list *loop_body = cmd.body (); - - string_vector keys = tmp_val.keys (); - - octave_idx_type nel = keys.numel (); - - for (octave_idx_type i = 0; i < nel; i++) - { - if (m_echo_state) - m_echo_file_pos = line; - - std::string key = keys[i]; - - const Cell val_lst = tmp_val.contents (key); - - octave_idx_type n = val_lst.numel (); - - octave_value val = (n == 1) ? val_lst(0) : octave_value (val_lst); - - val_ref.assign (octave_value::op_asn_eq, val); - key_ref.assign (octave_value::op_asn_eq, key); - - if (loop_body) - loop_body->accept (*this); - - if (quit_loop_now ()) - break; - } -} - -void tree_evaluator::visit_spmd_command (tree_spmd_command& cmd) -{ - // For now, we just execute the commands serially. - - tree_statement_list *body = cmd.body (); - - if (body) - body->accept (*this); -} - -octave_value -tree_evaluator::evaluate_anon_fcn_handle (tree_anon_fcn_handle& afh) -{ - // FIXME: should CMD_LIST be limited to a single expression? - // I think that is what Matlab does. - - symbol_scope new_scope; - symbol_scope scope = afh.scope (); - if (scope) - new_scope = scope.dup (); - - tree_parameter_list *param_list = afh.parameter_list (); - tree_parameter_list *param_list_dup - = param_list ? param_list->dup (new_scope) : nullptr; - - tree_parameter_list *ret_list = nullptr; - - tree_statement_list *stmt_list = nullptr; - - symbol_scope parent_scope = get_current_scope (); - - new_scope.set_parent (parent_scope); - new_scope.set_primary_parent (parent_scope); - - tree_expression *expr = afh.expression (); - if (expr) - { - tree_expression *expr_dup = expr->dup (new_scope); - tree_statement *stmt = new tree_statement (expr_dup, nullptr); - stmt_list = new tree_statement_list (stmt); - } - - tree_anon_scopes anon_fcn_ctx (afh); - - std::set free_vars = anon_fcn_ctx.free_variables (); - - stack_frame::local_vars_map local_vars; - - std::shared_ptr frame - = m_call_stack.get_current_stack_frame (); - - for (auto& name : free_vars) - { - octave_value val = frame->varval (name); - - if (val.is_defined ()) - local_vars[name] = val; - } - - octave_user_function *af - = new octave_user_function (new_scope, param_list_dup, ret_list, - stmt_list); - - octave_function *curr_fcn = m_call_stack.current_function (); - - bool is_nested = false; - - if (curr_fcn) - { - // FIXME: maybe it would be better to just stash curr_fcn - // instead of individual bits of info about it? - - // An anonymous function defined inside another nested function - // or parent of a nested function also behaves like a nested - // function. - - if (curr_fcn->is_parent_function () || curr_fcn->is_nested_function ()) - { - is_nested = true; - af->mark_as_nested_function (); - new_scope.set_nesting_depth (parent_scope.nesting_depth () + 1); - } - - af->stash_dir_name (curr_fcn->dir_name ()); - - new_scope.cache_fcn_file_name (curr_fcn->fcn_file_name ()); - new_scope.cache_dir_name (curr_fcn->dir_name ()); - - // The following is needed so that class method dispatch works - // properly for anonymous functions that wrap class methods. - - if (curr_fcn->is_class_method () || curr_fcn->is_class_constructor ()) - af->stash_dispatch_class (curr_fcn->dispatch_class ()); - - af->stash_fcn_file_name (curr_fcn->fcn_file_name ()); - } - - af->mark_as_anonymous_function (); - - octave_value ov_fcn (af); - - return (is_nested - ? octave_value (new octave_fcn_handle (ov_fcn, local_vars, frame)) - : octave_value (new octave_fcn_handle (ov_fcn, local_vars))); -} - -octave_value_list -tree_evaluator::execute_builtin_function (octave_builtin& builtin_function, - int nargout, - const octave_value_list& args) -{ - octave_value_list retval; - - if (args.has_magic_colon ()) - error ("invalid use of colon in function argument list"); - - profiler::enter block (m_profiler, builtin_function); - - octave_builtin::fcn fcn = builtin_function.function (); - - if (fcn) - retval = (*fcn) (args, nargout); - else - { - octave_builtin::meth meth = builtin_function.method (); - - retval = (*meth) (m_interpreter, args, nargout); - } - - // Do not allow null values to be returned from functions. - // FIXME: perhaps true builtins should be allowed? - - retval.make_storable_values (); - - // Fix the case of a single undefined value. - // This happens when a compiled function uses - // - // octave_value retval; - // - // instead of - // - // octave_value_list retval; - // - // the idiom is very common, so we solve that here. - - if (retval.length () == 1 && retval.xelem (0).is_undefined ()) - retval.clear (); - - return retval; -} - -octave_value_list -tree_evaluator::execute_mex_function (octave_mex_function& mex_function, - int nargout, - const octave_value_list& args) -{ - octave_value_list retval; - - if (args.has_magic_colon ()) - error ("invalid use of colon in function argument list"); - - profiler::enter block (m_profiler, mex_function); - - retval = call_mex (mex_function, args, nargout); - - return retval; -} - -octave_value_list -tree_evaluator::execute_user_script (octave_user_script& user_script, - int nargout, - const octave_value_list& args) -{ - octave_value_list retval; - - std::string file_name = user_script.fcn_file_name (); - - if (args.length () != 0 || nargout != 0) - error ("invalid call to script %s", file_name.c_str ()); - - tree_statement_list *cmd_list = user_script.body (); - - if (! cmd_list) - return retval; - - // FIXME: Maybe this check belongs in the places where we push a new - // stack frame? Or in the call_stack push method itself? - - if (m_call_stack.size () >= static_cast (m_max_recursion_depth)) - error ("max_recursion_depth exceeded"); - - unwind_protect_var upv (m_statement_context, SC_SCRIPT); - - profiler::enter block (m_profiler, user_script); - - if (echo ()) - push_echo_state (tree_evaluator::ECHO_SCRIPTS, file_name); - - // FIXME: Should we be using tree_evaluator::eval here? - - cmd_list->accept (*this); - - if (m_returning) - m_returning = 0; - - if (m_breaking) - m_breaking--; - - return retval; -} - -void -tree_evaluator::visit_octave_user_script (octave_user_script&) -{ - // ?? - panic_impossible (); -} - -octave_value_list -tree_evaluator::execute_user_function (octave_user_function& user_function, - int nargout, - const octave_value_list& xargs) -{ - octave_value_list retval; - - // If this function is a classdef constructor, extract the first input - // argument, which must be the partially constructed object instance. - - octave_value_list args (xargs); - octave_value_list ret_args; - - int nargin = args.length (); - - if (user_function.is_classdef_constructor ()) - { - if (nargin > 0) - { - ret_args = args.slice (0, 1, true); - --nargin; - args = args.slice (1, nargin, true); - } - else - panic_impossible (); - } - - // FIXME: this probably shouldn't be a double-precision matrix. - Matrix ignored_outputs = ignored_fcn_outputs (); - - tree_parameter_list *param_list = user_function.parameter_list (); - - bool takes_varargs = false; - int max_inputs = 0; - - if (param_list) - { - takes_varargs = param_list->takes_varargs (); - max_inputs = param_list->length (); - } - - if (! takes_varargs && nargin > max_inputs) - { - std::string name = user_function.name (); - - if (name.empty ()) - name = "@"; - - error_with_id ("Octave:invalid-fun-call", - "%s: function called with too many inputs", - name.c_str ()); - } - - define_parameter_list_from_arg_vector (param_list, args); - - tree_parameter_list *ret_list = user_function.return_list (); - - if (ret_list && ! ret_list->takes_varargs ()) - { - int max_outputs = ret_list->length (); - - if (nargout > max_outputs) - { - std::string name = user_function.name (); - - error_with_id ("Octave:invalid-fun-call", - "%s: function called with too many outputs", - name.c_str ()); - } - } - - bind_auto_fcn_vars (xargs.name_tags (), ignored_outputs, nargin, - nargout, user_function.takes_varargs (), - user_function.all_va_args (args)); - - // For classdef constructor, pre-populate the output arguments - // with the pre-initialized object instance, extracted above. - - if (user_function.is_classdef_constructor ()) - { - if (! ret_list) - error ("%s: invalid classdef constructor, no output argument defined", - user_function.dispatch_class ().c_str ()); - - define_parameter_list_from_arg_vector (ret_list, ret_args); - } - - // FIXME: Maybe this check belongs in the places where we push a - // new stack frame? Or in the call_stack push method itself? - - if (m_call_stack.size () >= static_cast (m_max_recursion_depth)) - error ("max_recursion_depth exceeded"); - - unwind_action act2 ([&user_function] () - { - user_function.restore_warning_states (); - }); - - // Evaluate the commands that make up the function. - - unwind_protect_var upv (m_statement_context, SC_FUNCTION); - - tree_statement_list *cmd_list = user_function.body (); - - if (cmd_list) - { - profiler::enter - block (m_profiler, user_function); - - if (echo ()) - push_echo_state (tree_evaluator::ECHO_FUNCTIONS, - user_function.fcn_file_name ()); - - if (user_function.is_special_expr ()) - { - panic_if (cmd_list->length () != 1); - - tree_statement *stmt = cmd_list->front (); - - tree_expression *expr = stmt->expression (); - - if (expr) - { - m_call_stack.set_location (stmt->line (), stmt->column ()); - - retval = expr->evaluate_n (*this, nargout); - } - } - else - cmd_list->accept (*this); - - if (m_returning) - m_returning = 0; - - if (m_breaking) - m_breaking--; - } - - // Copy return values out. - - if (ret_list && ! user_function.is_special_expr ()) - { - Cell varargout; - - if (ret_list->takes_varargs ()) - { - octave_value varargout_varval = varval ("varargout"); - - if (varargout_varval.is_defined ()) - varargout = varargout_varval.xcell_value ("varargout must be a cell array object"); - } - - retval = convert_return_list_to_const_vector (ret_list, nargout, - ignored_outputs, - varargout); - } - - return retval; -} - -void -tree_evaluator::visit_octave_user_function (octave_user_function&) -{ - // ?? - panic_impossible (); -} - -void -tree_evaluator::visit_octave_user_function_header (octave_user_function&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_octave_user_function_trailer (octave_user_function&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_function_def (tree_function_def& cmd) -{ - octave_value fcn = cmd.function (); - - octave_function *f = fcn.function_value (); - - if (f) - { - std::string nm = f->name (); - - symbol_table& symtab = m_interpreter.get_symbol_table (); - - symtab.install_cmdline_function (nm, fcn); - - // Make sure that any variable with the same name as the new - // function is cleared. - - assign (nm); - } -} - -void -tree_evaluator::visit_identifier (tree_identifier&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_if_clause (tree_if_clause&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_if_command (tree_if_command& cmd) -{ - if (m_echo_state) - { - int line = cmd.line (); - if (line < 0) - line = 1; - echo_code (line); - m_echo_file_pos = line + 1; - } - - // FIXME: tree_if_command_list is not derived from tree, so should it - // really have an accept method? - - tree_if_command_list *lst = cmd.cmd_list (); - - if (lst) - lst->accept (*this); -} - -void -tree_evaluator::visit_if_command_list (tree_if_command_list& lst) -{ - for (tree_if_clause *tic : lst) - { - tree_expression *expr = tic->condition (); - - if (! (in_debug_repl () - && m_call_stack.current_frame () == m_debug_frame)) - m_call_stack.set_location (tic->line (), tic->column ()); - - if (m_debug_mode && ! tic->is_else_clause ()) - do_breakpoint (tic->is_active_breakpoint (*this)); - - if (tic->is_else_clause () || is_logically_true (expr, "if")) - { - tree_statement_list *stmt_lst = tic->commands (); - - if (stmt_lst) - stmt_lst->accept (*this); - - break; - } - } -} - -void -tree_evaluator::visit_index_expression (tree_index_expression&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_matrix (tree_matrix&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_cell (tree_cell&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_multi_assignment (tree_multi_assignment&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_no_op_command (tree_no_op_command& cmd) -{ - if (m_echo_state) - { - int line = cmd.line (); - if (line < 0) - line = 1; - echo_code (line); - m_echo_file_pos = line + 1; - } - - if (m_debug_mode && cmd.is_end_of_fcn_or_script ()) - do_breakpoint (cmd.is_active_breakpoint (*this), true); -} - -void -tree_evaluator::visit_constant (tree_constant&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_fcn_handle (tree_fcn_handle&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_parameter_list (tree_parameter_list&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_postfix_expression (tree_postfix_expression&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_prefix_expression (tree_prefix_expression&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_return_command (tree_return_command& cmd) -{ - if (m_echo_state) - { - int line = cmd.line (); - if (line < 0) - line = 1; - echo_code (line); - m_echo_file_pos = line + 1; - } - - if (m_debug_mode) - do_breakpoint (cmd.is_active_breakpoint (*this)); - - // Act like dbcont. - - if (in_debug_repl () && m_call_stack.current_frame () == m_debug_frame) - dbcont (); - else if (m_statement_context == SC_FUNCTION - || m_statement_context == SC_SCRIPT - || m_in_loop_command) - m_returning = 1; -} - -void -tree_evaluator::visit_simple_assignment (tree_simple_assignment&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_statement (tree_statement& stmt) -{ - tree_command *cmd = stmt.command (); - tree_expression *expr = stmt.expression (); - - if (cmd || expr) - { - if (! (in_debug_repl () - && m_call_stack.current_frame () == m_debug_frame)) - m_call_stack.set_location (stmt.line (), stmt.column ()); - - try - { - if (cmd) - { - unwind_protect_var *> - upv (m_lvalue_list, nullptr); - - cmd->accept (*this); - } - else - { - if (m_echo_state) - { - int line = stmt.line (); - if (line < 0) - line = 1; - echo_code (line); - m_echo_file_pos = line + 1; - } - - if (m_debug_mode) - do_breakpoint (expr->is_active_breakpoint (*this)); - - // FIXME: maybe all of this should be packaged in - // one virtual function that returns a flag saying whether - // or not the expression will take care of binding ans and - // printing the result. - - // FIXME: it seems that we should just have to - // evaluate the expression and that should take care of - // everything, binding ans as necessary? - - octave_value tmp_result = expr->evaluate (*this, 0); - - if (tmp_result.is_defined ()) - { - bool do_bind_ans = false; - - if (expr->is_identifier ()) - do_bind_ans = ! is_variable (expr); - else - do_bind_ans = ! expr->is_assignment_expression (); - - if (do_bind_ans) - bind_ans (tmp_result, expr->print_result () - && statement_printing_enabled ()); - } - } - } - catch (const std::bad_alloc&) - { - // FIXME: We want to use error_with_id here so that give users - // control over this error message but error_with_id will - // require some memory allocations. Is there anything we can - // do to make those more likely to succeed? - - error_with_id ("Octave:bad-alloc", - "out of memory or dimension too large for Octave's index type"); - } - catch (const interrupt_exception&) - { - // If we are debugging, then continue with next statement. - // Otherwise, jump out of here. - - if (m_debug_mode) - m_interpreter.recover_from_exception (); - else - throw; - } - catch (const execution_exception& ee) - { - error_system& es = m_interpreter.get_error_system (); - - if ((m_interpreter.interactive () - || application::forced_interactive ()) - && ((es.debug_on_error () - && m_bp_table.debug_on_err (es.last_error_id ())) - || (es.debug_on_caught () - && m_bp_table.debug_on_caught (es.last_error_id ()))) - && in_user_code ()) - { - es.save_exception (ee); - es.display_exception (ee); - - enter_debugger (); - - // It doesn't make sense to continue execution after an - // error occurs so force the debugger to quit all debug - // levels and return the the top prompt. - - throw quit_debug_exception (true); - } - else - throw; - } - } -} - -void -tree_evaluator::visit_statement_list (tree_statement_list& lst) -{ - // FIXME: commented out along with else clause below. - // static octave_value_list empty_list; - - auto p = lst.begin (); - - if (p != lst.end ()) - { - while (true) - { - tree_statement *elt = *p++; - - if (! elt) - error ("invalid statement found in statement list!"); - - octave_quit (); - - elt->accept (*this); - - if (m_breaking || m_continuing) - break; - - if (m_returning) - break; - - if (p == lst.end ()) - break; - else - { - // Clear previous values before next statement is - // evaluated so that we aren't holding an extra - // reference to a value that may be used next. For - // example, in code like this: - // - // X = rand (N); # refcount for X should be 1 - // # after this statement - // - // X(idx) = val; # no extra copy of X should be - // # needed, but we will be faked - // # out if retval is not cleared - // # between statements here - - // result_values = empty_list; - } + print_usage (); } - } -} - -void -tree_evaluator::visit_switch_case (tree_switch_case&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_switch_case_list (tree_switch_case_list&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_switch_command (tree_switch_command& cmd) -{ - if (m_echo_state) - { - int line = cmd.line (); - if (line < 0) - line = 1; - echo_code (line); - m_echo_file_pos = line + 1; - } - - if (m_debug_mode) - do_breakpoint (cmd.is_active_breakpoint (*this)); - - tree_expression *expr = cmd.switch_value (); - - if (! expr) - error ("missing value in switch command near line %d, column %d", - cmd.line (), cmd.column ()); - - octave_value val = expr->evaluate (*this); - - tree_switch_case_list *lst = cmd.case_list (); - - if (lst) - { - for (tree_switch_case *t : *lst) - { - if (t->is_default_case () || switch_case_label_matches (t, val)) - { - tree_statement_list *stmt_lst = t->commands (); - - if (stmt_lst) - stmt_lst->accept (*this); - - break; - } - } - } -} - -void -tree_evaluator::visit_try_catch_command (tree_try_catch_command& cmd) -{ - if (m_echo_state) - { - int line = cmd.line (); - if (line < 0) - line = 1; - echo_code (line); - m_echo_file_pos = line + 1; - } - - bool execution_error = false; - octave_scalar_map err_map; - - tree_statement_list *try_code = cmd.body (); - - if (try_code) - { - // unwind frame before catch block - - unwind_protect frame; - - interpreter_try (frame); - - // The catch code is *not* added to unwind_protect stack; it - // doesn't need to be run on interrupts. - - try - { - try_code->accept (*this); - } - catch (const execution_exception& ee) - { - execution_error = true; - - error_system& es = m_interpreter.get_error_system (); - - es.save_exception (ee); - - err_map.assign ("message", es.last_error_message ()); - err_map.assign ("identifier", es.last_error_id ()); - err_map.assign ("stack", es.last_error_stack ()); - - m_interpreter.recover_from_exception (); - } - - // Actions attached to unwind_protect frame will run here, prior - // to executing the catch block. - } - - if (execution_error) - { - tree_statement_list *catch_code = cmd.cleanup (); - - if (catch_code) - { - tree_identifier *expr_id = cmd.identifier (); - - if (expr_id) - { - octave_lvalue ult = expr_id->lvalue (*this); - - ult.assign (octave_value::op_asn_eq, err_map); - } - - // perform actual "catch" block - catch_code->accept (*this); - } - } -} - -void -tree_evaluator::do_unwind_protect_cleanup_code (tree_statement_list *list) -{ - unwind_protect frame; - - frame.protect_var (octave_interrupt_state); - octave_interrupt_state = 0; - - // We want to preserve the last location info for possible - // backtracking. - - frame.add (&call_stack::set_line, &m_call_stack, - m_call_stack.current_line ()); - - frame.add (&call_stack::set_column, &m_call_stack, - m_call_stack.current_column ()); - - // Similarly, if we have seen a return or break statement, allow all - // the cleanup code to run before returning or handling the break. - // We don't have to worry about continue statements because they can - // only occur in loops. - - frame.protect_var (m_returning); - m_returning = 0; - - frame.protect_var (m_breaking); - m_breaking = 0; - - try - { - if (list) - list->accept (*this); - } - catch (const execution_exception& ee) - { - error_system& es = m_interpreter.get_error_system (); - - es.save_exception (ee); - m_interpreter.recover_from_exception (); - - if (m_breaking || m_returning) - frame.discard (2); - else - frame.run (2); - - frame.discard (2); - - throw; - } - - // The unwind_protects are popped off the stack in the reverse of - // the order they are pushed on. - - // FIXME: these statements say that if we see a break or - // return statement in the cleanup block, that we want to use the - // new value of the breaking or returning flag instead of restoring - // the previous value. Is that the right thing to do? I think so. - // Consider the case of - // - // function foo () - // unwind_protect - // fprintf (stderr, "1: this should always be executed\n"); - // break; - // fprintf (stderr, "1: this should never be executed\n"); - // unwind_protect_cleanup - // fprintf (stderr, "2: this should always be executed\n"); - // return; - // fprintf (stderr, "2: this should never be executed\n"); - // end_unwind_protect - // endfunction - // - // If we reset the value of the breaking flag, both the returning - // flag and the breaking flag will be set, and we shouldn't have - // both. So, use the most recent one. If there is no return or - // break in the cleanup block, the values should be reset to - // whatever they were when the cleanup block was entered. - - if (m_breaking || m_returning) - frame.discard (2); - else - frame.run (2); -} - -void -tree_evaluator::visit_unwind_protect_command (tree_unwind_protect_command& cmd) -{ - if (m_echo_state) - { - int line = cmd.line (); - if (line < 0) - line = 1; - echo_code (line); - m_echo_file_pos = line + 1; - } - - tree_statement_list *cleanup_code = cmd.cleanup (); - - tree_statement_list *unwind_protect_code = cmd.body (); - - if (unwind_protect_code) - { - try - { - unwind_protect_code->accept (*this); - } - catch (const execution_exception& ee) - { - error_system& es = m_interpreter.get_error_system (); - - // FIXME: Maybe we should be able to temporarily set the - // interpreter's exception handling state to something "safe" - // while the cleanup block runs instead of just resetting it - // here? - es.save_exception (ee); - m_interpreter.recover_from_exception (); - - // Run the cleanup code on exceptions, so that it is run even - // in case of interrupt or out-of-memory. - do_unwind_protect_cleanup_code (cleanup_code); - - // If an error occurs inside the cleanup code, a new - // exception will be thrown instead of the original. - throw; - } - catch (const interrupt_exception&) - { - // The comments above apply here as well. - m_interpreter.recover_from_exception (); - do_unwind_protect_cleanup_code (cleanup_code); - throw; - } - - // Also execute the unwind_protect_cleanump code if the - // unwind_protect block runs without error. - do_unwind_protect_cleanup_code (cleanup_code); - } -} - -void -tree_evaluator::visit_while_command (tree_while_command& cmd) -{ - int line = cmd.line (); - if (line < 0) - line = 1; - - if (m_echo_state) - { - echo_code (line); - line++; - } - - unwind_protect_var upv (m_in_loop_command, true); - - tree_expression *expr = cmd.condition (); - - if (! expr) - panic_impossible (); - - for (;;) - { - if (m_echo_state) - m_echo_file_pos = line; - - if (m_debug_mode) - do_breakpoint (cmd.is_active_breakpoint (*this)); - - if (is_logically_true (expr, "while")) - { - tree_statement_list *loop_body = cmd.body (); - - if (loop_body) - loop_body->accept (*this); - - if (quit_loop_now ()) - break; - } - else break; - } -} - -void -tree_evaluator::visit_do_until_command (tree_do_until_command& cmd) -{ - int line = cmd.line (); - if (line < 0) - line = 1; - - if (m_echo_state) - { - echo_code (line); - line++; - } - - unwind_protect_var upv (m_in_loop_command, true); - - tree_expression *expr = cmd.condition (); - - if (! expr) - panic_impossible (); - - for (;;) - { - if (m_echo_state) - m_echo_file_pos = line; - - tree_statement_list *loop_body = cmd.body (); - - if (loop_body) - loop_body->accept (*this); - - if (quit_loop_now ()) - break; - - if (m_debug_mode) - do_breakpoint (cmd.is_active_breakpoint (*this)); - - if (is_logically_true (expr, "do-until")) + + default: + print_usage (); break; - } -} - -void -tree_evaluator::visit_superclass_ref (tree_superclass_ref&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_metaclass_query (tree_metaclass_query&) -{ - panic_impossible (); -} - -void tree_evaluator::bind_ans (const octave_value& val, bool print) -{ - static std::string ans = "ans"; - - if (val.is_defined ()) - { - if (val.is_cs_list ()) - { - octave_value_list lst = val.list_value (); - - for (octave_idx_type i = 0; i < lst.length (); i++) - bind_ans (lst(i), print); - } - else - { - // FIXME: Maybe assign could also return the assigned value, - // just for convenience? - - assign (ans, val); - - if (print) - { - // Use varval instead of displaying VAL directly so that - // we get the right type and value for things like - // magic_int values that may mutate when stored. - - octave_value_list args = ovl (varval (ans)); - args.stash_name_tags (string_vector (ans)); - feval ("display", args); - } - } - } -} - -void -tree_evaluator::do_breakpoint (tree_statement& stmt) -{ - do_breakpoint (stmt.is_active_breakpoint (*this), - stmt.is_end_of_fcn_or_script ()); -} - -void -tree_evaluator::do_breakpoint (bool is_breakpoint, - bool is_end_of_fcn_or_script) -{ - bool break_on_this_statement = false; - - if (is_breakpoint) - break_on_this_statement = true; - else if (m_dbstep_flag > 0) - { - if (m_call_stack.current_frame () == m_debug_frame) - { - if (m_dbstep_flag == 1 || is_end_of_fcn_or_script) - { - // We get here if we are doing a "dbstep" or a "dbstep N" and - // the count has reached 1 so that we must stop and return to - // debug prompt. Alternatively, "dbstep N" has been used but - // the end of the frame has been reached so we stop at the last - // line and return to prompt. - - break_on_this_statement = true; - } - else - { - // Executing "dbstep N". Decrease N by one and continue. - - m_dbstep_flag--; - } - - } - else if (m_dbstep_flag == 1 - && m_call_stack.current_frame () < m_debug_frame) - { - // We stepped out from the end of a function. - - m_debug_frame = m_call_stack.current_frame (); - - break_on_this_statement = true; - } - } - else if (m_dbstep_flag == -1) - { - // We get here if we are doing a "dbstep in". - - break_on_this_statement = true; - - m_debug_frame = m_call_stack.current_frame (); - } - else if (m_dbstep_flag == -2) - { - // We get here if we are doing a "dbstep out". Check for end of - // function and whether the current frame is the same as the - // cached value because we want to step out from the frame where - // "dbstep out" was evaluated, not from any functions called from - // that frame. - - if (is_end_of_fcn_or_script - && m_call_stack.current_frame () == m_debug_frame) - m_dbstep_flag = -1; - } - - if (! break_on_this_statement) - break_on_this_statement = m_break_on_next_stmt; - - m_break_on_next_stmt = false; - - if (break_on_this_statement) - { - m_dbstep_flag = 0; - - enter_debugger (); - } -} - -bool -tree_evaluator::is_logically_true (tree_expression *expr, - const char *warn_for) -{ - bool expr_value = false; - - m_call_stack.set_location (expr->line (), expr->column ()); - - octave_value t1 = expr->evaluate (*this); - - if (t1.is_defined ()) - return t1.is_true (); - else - error ("%s: undefined value used in conditional expression", warn_for); - - return expr_value; -} - -octave_value -tree_evaluator::max_recursion_depth (const octave_value_list& args, - int nargout) -{ - return set_internal_variable (m_max_recursion_depth, args, nargout, - "max_recursion_depth", 0); -} - -symbol_info_list -tree_evaluator::glob_symbol_info (const std::string& pattern) const -{ - return m_call_stack.glob_symbol_info (pattern); -} - -symbol_info_list -tree_evaluator::regexp_symbol_info (const std::string& pattern) const -{ - return m_call_stack.regexp_symbol_info (pattern); -} - -symbol_info_list -tree_evaluator::get_symbol_info (void) -{ - return m_call_stack.get_symbol_info (); -} - -symbol_info_list -tree_evaluator::top_scope_symbol_info (void) const -{ - return m_call_stack.top_scope_symbol_info (); -} - -octave_map tree_evaluator::get_autoload_map (void) const -{ - Cell fcn_names (dim_vector (m_autoload_map.size (), 1)); - Cell file_names (dim_vector (m_autoload_map.size (), 1)); - - octave_idx_type i = 0; - for (const auto& fcn_fname : m_autoload_map) - { - fcn_names(i) = fcn_fname.first; - file_names(i) = fcn_fname.second; - - i++; - } - - octave_map m; - - m.assign ("function", fcn_names); - m.assign ("file", file_names); - - return m; -} - -std::string tree_evaluator::lookup_autoload (const std::string& nm) const -{ - std::string retval; - - auto p = m_autoload_map.find (nm); - - if (p != m_autoload_map.end ()) - { - load_path& lp = m_interpreter.get_load_path (); - - retval = lp.find_file (p->second); - } - - return retval; -} - -std::list tree_evaluator::autoloaded_functions (void) const -{ - std::list names; - - for (const auto& fcn_fname : m_autoload_map) - names.push_back (fcn_fname.first); - - return names; -} - -std::list -tree_evaluator::reverse_lookup_autoload (const std::string& nm) const -{ - std::list names; - - for (const auto& fcn_fname : m_autoload_map) - if (nm == fcn_fname.second) - names.push_back (fcn_fname.first); - - return names; -} - -void tree_evaluator::add_autoload (const std::string& fcn, - const std::string& nm) -{ - std::string file_name = check_autoload_file (nm); - - m_autoload_map[fcn] = file_name; -} - -void tree_evaluator::remove_autoload (const std::string& fcn, - const std::string& nm) -{ - check_autoload_file (nm); - - // Remove function from symbol table and autoload map. - symbol_table& symtab = m_interpreter.get_symbol_table (); - - symtab.clear_dld_function (fcn); - - m_autoload_map.erase (fcn); -} - -octave_value -tree_evaluator::whos_line_format (const octave_value_list& args, int nargout) -{ - return set_internal_variable (m_whos_line_format, args, nargout, - "whos_line_format"); -} - -octave_value -tree_evaluator::silent_functions (const octave_value_list& args, int nargout) -{ - return set_internal_variable (m_silent_functions, args, nargout, - "silent_functions"); -} - -octave_value -tree_evaluator::string_fill_char (const octave_value_list& args, int nargout) -{ - return set_internal_variable (m_string_fill_char, args, nargout, - "string_fill_char"); -} - -// Final step of processing an indexing error. Add the name of the -// variable being indexed, if any, then issue an error. (Will this also -// be needed by pt-lvalue, which calls subsref?) - -void tree_evaluator::final_index_error (index_exception& ie, - const tree_expression *expr) -{ - std::string extra_message; - - if (is_variable (expr)) - { - std::string var = expr->name (); - - ie.set_var (var); - - symbol_table& symtab = m_interpreter.get_symbol_table (); - - octave_value fcn = symtab.find_function (var); - - if (fcn.is_function ()) - { - octave_function *fp = fcn.function_value (); - - if (fp && fp->name () == var) - extra_message - = " (note: variable '" + var + "' shadows function)"; - } - } - - std::string msg = ie.message () + extra_message; - - error_with_id (ie.err_id (), "%s", msg.c_str ()); -} - -octave_value -tree_evaluator::do_who (int argc, const string_vector& argv, - bool return_list, bool verbose) -{ - return m_call_stack.do_who (argc, argv, return_list, verbose); -} - -octave_value_list -tree_evaluator::make_value_list (tree_argument_list *args, - const string_vector& arg_nm) -{ - octave_value_list retval; - - if (args) - { - unwind_protect_var *> - upv (m_lvalue_list, nullptr); - - int len = args->length (); - - unwind_protect_var upv2 (m_index_position); - unwind_protect_var upv3 (m_num_indices); - - m_num_indices = len; - - std::list arg_vals; - - int k = 0; - - for (auto elt : *args) - { - // FIXME: is it possible for elt to be invalid? - - if (! elt) - break; - - m_index_position = k++; - - octave_value tmp = elt->evaluate (*this); - - if (tmp.is_cs_list ()) - { - octave_value_list tmp_ovl = tmp.list_value (); - - for (octave_idx_type i = 0; i < tmp_ovl.length (); i++) - arg_vals.push_back (tmp_ovl(i)); - } - else if (tmp.is_defined ()) - arg_vals.push_back (tmp); - } - - retval = octave_value_list (arg_vals); - } - - octave_idx_type n = retval.length (); - - if (n > 0) - retval.stash_name_tags (arg_nm); - - return retval; -} - -std::list -tree_evaluator::make_lvalue_list (tree_argument_list *lhs) -{ - std::list retval; - - for (tree_expression *elt : *lhs) - retval.push_back (elt->lvalue (*this)); - - return retval; -} - -void -tree_evaluator::push_echo_state (int type, const std::string& file_name, - int pos) -{ - unwind_protect *frame = m_call_stack.curr_fcn_unwind_protect_frame (); - - if (frame) - { - push_echo_state_cleanup (*frame); - - set_echo_state (type, file_name, pos); - } -} - -void -tree_evaluator::set_echo_state (int type, const std::string& file_name, - int pos) -{ - m_echo_state = echo_this_file (file_name, type); - m_echo_file_name = file_name; - m_echo_file_pos = pos; -} - -void -tree_evaluator::uwp_set_echo_state (bool state, const std::string& file_name, - int pos) -{ - m_echo_state = state; - m_echo_file_name = file_name; - m_echo_file_pos = pos; -} - -void -tree_evaluator::maybe_set_echo_state (void) -{ - octave_function *caller = caller_function (); - - if (caller && caller->is_user_code ()) - { - octave_user_code *fcn = dynamic_cast (caller); - - int type = fcn->is_user_function () ? ECHO_FUNCTIONS : ECHO_SCRIPTS; - - std::string file_name = fcn->fcn_file_name (); - - // We want the line where "echo" was called, not the line number - // stored in the stack frame that was created for the echo - // function (that will always be -1). - - int pos = m_call_stack.current_user_code_line (); - - if (pos < 0) - pos = 1; - - set_echo_state (type, file_name, pos); - } -} - -void -tree_evaluator::push_echo_state_cleanup (unwind_protect& frame) -{ - frame.add (&tree_evaluator::uwp_set_echo_state, this, - m_echo_state, m_echo_file_name, m_echo_file_pos); -} - -bool tree_evaluator::maybe_push_echo_state_cleanup (void) -{ - // This function is expected to be called from ECHO, which would be - // the top of the call stack. If the caller of ECHO is a - // user-defined function or script, then set up unwind-protect - // elements to restore echo state. - - unwind_protect *frame = m_call_stack.curr_fcn_unwind_protect_frame (); - - if (frame) - { - push_echo_state_cleanup (*frame); - return true; - } - - return false; -} - - -octave_value -tree_evaluator::echo (const octave_value_list& args, int) -{ - bool cleanup_pushed = maybe_push_echo_state_cleanup (); - - string_vector argv = args.make_argv (); - - switch (args.length ()) - { - case 0: - if ((m_echo & ECHO_SCRIPTS) || (m_echo & ECHO_FUNCTIONS)) - { - m_echo = ECHO_OFF; - m_echo_files.clear (); - } - else - m_echo = ECHO_SCRIPTS; - break; - - case 1: + } + + if (cleanup_pushed) + maybe_set_echo_state (); + + return octave_value (); + } + + bool tree_evaluator::in_debug_repl (void) const + { + return (m_debugger_stack.empty () + ? false : m_debugger_stack.top()->in_debug_repl ()); + } + + void tree_evaluator::dbcont (void) + { + if (! m_debugger_stack.empty ()) + m_debugger_stack.top()->dbcont (); + } + + void tree_evaluator::dbquit (bool all) + { + if (! m_debugger_stack.empty ()) + m_debugger_stack.top()->dbquit (all); + } + + static octave_value end_value (const octave_value& value, + octave_idx_type index_position, + octave_idx_type num_indices) + { + dim_vector dv = value.dims (); + int ndims = dv.ndims (); + + if (num_indices < ndims) { - std::string arg0 = argv[0]; - - if (arg0 == "on") - m_echo = ECHO_SCRIPTS; - else if (arg0 == "off") - m_echo = ECHO_OFF; + for (int i = num_indices; i < ndims; i++) + dv(num_indices-1) *= dv(i); + + if (num_indices == 1) + { + ndims = 2; + dv.resize (ndims); + dv(1) = 1; + } else { - std::string file = fcn_file_in_path (arg0); - file = sys::env::make_absolute (file); - - if (file.empty ()) - error ("echo: no such file %s", arg0.c_str ()); - - if (m_echo & ECHO_ALL) - { - // Echo is enabled for all functions, so turn it off - // for this one. - - m_echo_files[file] = false; - } - else + ndims = num_indices; + dv.resize (ndims); + } + } + + return (index_position < ndims + ? octave_value (dv(index_position)) : octave_value (1.0)); + } + + octave_value_list + tree_evaluator::evaluate_end_expression (const octave_value_list& args) + { + int nargin = args.length (); + + if (nargin != 0 && nargin != 3) + print_usage (); + + if (nargin == 3) + { + octave_idx_type index_position + = args(1).xidx_type_value ("end: K must be integer value"); + + if (index_position < 1) + error ("end: K must be greater than zero"); + + octave_idx_type num_indices + = args(2).xidx_type_value ("end: N must be integer value"); + + if (num_indices < 1) + error ("end: N must be greater than zero"); + + return end_value (args(0), index_position-1, num_indices); + } + + // If m_indexed_object is undefined, then this use of 'end' is + // either appearing in a function call argument list or in an + // attempt to index an undefined symbol. There seems to be no + // reasonable way to provide a better error message. So just fail + // with an invalid use message. See bug #58830. + + if (m_indexed_object.is_undefined ()) + error ("invalid use of 'end': may only be used to index existing value"); + + octave_value expr_result; + + if (m_index_list.empty ()) + expr_result = m_indexed_object; + else + { + try + { + // When evaluating "end" with no arguments, we should have + // been called from the built-in Fend function that appears + // in the context of an argument list. Fend will be + // evaluated in its own stack frame. But we need to + // evaluate the partial expression that the special "end" + // token applies to in the calling stack frame. + + unwind_action act ([=] (std::size_t frm) + { + m_call_stack.restore_frame (frm); + }, m_call_stack.current_frame ()); + + std::size_t n = m_call_stack.find_current_user_frame (); + m_call_stack.goto_frame (n); + + // End is only valid inside argument lists used for + // indexing. The dispatch class is set by the function that + // evaluates the argument list. + + // Silently ignore extra output values. + + octave_value_list tmp + = m_indexed_object.subsref (m_index_type, m_index_list, 1); + + expr_result = tmp.length () ? tmp(0) : octave_value (); + + if (expr_result.is_cs_list ()) + err_indexed_cs_list (); + } + catch (const index_exception&) + { + error ("error evaluating partial expression for END"); + } + } + + if (expr_result.isobject ()) + { + // FIXME: is there a better way to lookup and execute a method + // that handles all the details like setting the dispatch class + // appropriately? + + std::string dispatch_class = expr_result.class_name (); + + symbol_table& symtab = m_interpreter.get_symbol_table (); + + octave_value meth = symtab.find_method ("end", dispatch_class); + + if (meth.is_defined ()) + return m_interpreter.feval + (meth, ovl (expr_result, m_index_position+1, m_num_indices), 1); + } + + return end_value (expr_result, m_index_position, m_num_indices); + } + + octave_value + tree_evaluator::PS4 (const octave_value_list& args, int nargout) + { + return set_internal_variable (m_PS4, args, nargout, "PS4"); + } + + bool tree_evaluator::echo_this_file (const std::string& file, int type) const + { + if ((type & m_echo) == ECHO_SCRIPTS) + { + // Asking about scripts and echo is enabled for them. + return true; + } + + if ((type & m_echo) == ECHO_FUNCTIONS) + { + // Asking about functions and echo is enabled for functions. + // Now, which ones? + + auto p = m_echo_files.find (file); + + if (m_echo & ECHO_ALL) + { + // Return true ulness echo was turned off for a specific + // file. + + return (p == m_echo_files.end () || p->second); + } + else + { + // Return true if echo is specifically enabled for this file. + + return p != m_echo_files.end () && p->second; + } + } + + return false; + } + + void tree_evaluator::echo_code (int line) + { + std::string prefix = command_editor::decode_prompt_string (m_PS4); + + octave_function *curr_fcn = m_call_stack.current_function (); + + if (curr_fcn && curr_fcn->is_user_code ()) + { + octave_user_code *code = dynamic_cast (curr_fcn); + + int num_lines = line - m_echo_file_pos + 1; + + std::deque lines + = code->get_code_lines (m_echo_file_pos, num_lines); + + for (auto& elt : lines) + octave_stdout << prefix << elt << std::endl; + } + } + + // Decide if it's time to quit a for or while loop. + bool tree_evaluator::quit_loop_now (void) + { + octave_quit (); + + // Maybe handle 'continue N' someday... + + if (m_continuing) + m_continuing--; + + bool quit = (m_returning || m_breaking || m_continuing); + + if (m_breaking) + m_breaking--; + + return quit; + } + + void tree_evaluator::bind_auto_fcn_vars (const string_vector& arg_names, + const Matrix& ignored_outputs, + int nargin, int nargout, + bool takes_varargs, + const octave_value_list& va_args) + { + set_auto_fcn_var (stack_frame::ARG_NAMES, Cell (arg_names)); + set_auto_fcn_var (stack_frame::IGNORED, ignored_outputs); + set_auto_fcn_var (stack_frame::NARGIN, nargin); + set_auto_fcn_var (stack_frame::NARGOUT, nargout); + set_auto_fcn_var (stack_frame::SAVED_WARNING_STATES, octave_value ()); + + if (takes_varargs) + assign ("varargin", va_args.cell_value ()); + } + + std::string + tree_evaluator::check_autoload_file (const std::string& nm) const + { + if (sys::env::absolute_pathname (nm)) + return nm; + + std::string full_name = nm; + + octave_user_code *fcn = m_call_stack.current_user_code (); + + bool found = false; + + if (fcn) + { + std::string fname = fcn->fcn_file_name (); + + if (! fname.empty ()) + { + fname = sys::env::make_absolute (fname); + fname = fname.substr (0, fname.find_last_of (sys::file_ops::dir_sep_str ()) + 1); + + sys::file_stat fs (fname + nm); + + if (fs.exists ()) { - // Echo may be enabled for specific functions. - - auto p = m_echo_files.find (file); - - if (p == m_echo_files.end ()) - { - // Not this one, so enable it. - - m_echo |= ECHO_FUNCTIONS; - m_echo_files[file] = true; - } - else - { - // This one is already in the list. Flip the - // status for it. - - p->second = ! p->second; - } + full_name = fname + nm; + found = true; } } } - break; - - case 2: - { - std::string arg0 = argv[0]; - std::string arg1 = argv[1]; - - if (arg1 == "on" || arg1 == "off") - std::swap (arg0, arg1); - - if (arg0 == "on") - { - if (arg1 == "all") - { - m_echo = (ECHO_SCRIPTS | ECHO_FUNCTIONS | ECHO_ALL); - m_echo_files.clear (); - } - else - { - std::string file = fcn_file_in_path (arg1); - file = sys::env::make_absolute (file); - - if (file.empty ()) - error ("echo: no such file %s", arg1.c_str ()); - - m_echo |= ECHO_FUNCTIONS; - m_echo_files[file] = true; - } - } - else if (arg0 == "off") - { - if (arg1 == "all") - { - m_echo = ECHO_OFF; - m_echo_files.clear (); - } - else - { - std::string file = fcn_file_in_path (arg1); - file = sys::env::make_absolute (file); - - if (file.empty ()) - error ("echo: no such file %s", arg1.c_str ()); - - m_echo_files[file] = false; - } - } - else - print_usage (); - } - break; - - default: - print_usage (); - break; - } - - if (cleanup_pushed) - maybe_set_echo_state (); - - return octave_value (); -} - -bool tree_evaluator::in_debug_repl (void) const -{ - return (m_debugger_stack.empty () - ? false : m_debugger_stack.top()->in_debug_repl ()); -} - -void tree_evaluator::dbcont (void) -{ - if (! m_debugger_stack.empty ()) - m_debugger_stack.top()->dbcont (); -} - -void tree_evaluator::dbquit (bool all) -{ - if (! m_debugger_stack.empty ()) - m_debugger_stack.top()->dbquit (all); -} - -static octave_value end_value (const octave_value& value, - octave_idx_type index_position, - octave_idx_type num_indices) -{ - dim_vector dv = value.dims (); - int ndims = dv.ndims (); - - if (num_indices < ndims) - { - for (int i = num_indices; i < ndims; i++) - dv(num_indices-1) *= dv(i); - - if (num_indices == 1) - { - ndims = 2; - dv.resize (ndims); - dv(1) = 1; - } - else - { - ndims = num_indices; - dv.resize (ndims); - } - } - - return (index_position < ndims - ? octave_value (dv(index_position)) : octave_value (1.0)); -} - -octave_value_list -tree_evaluator::evaluate_end_expression (const octave_value_list& args) -{ - int nargin = args.length (); - - if (nargin != 0 && nargin != 3) - print_usage (); - - if (nargin == 3) - { - octave_idx_type index_position - = args(1).xidx_type_value ("end: K must be integer value"); - - if (index_position < 1) - error ("end: K must be greater than zero"); - - octave_idx_type num_indices - = args(2).xidx_type_value ("end: N must be integer value"); - - if (num_indices < 1) - error ("end: N must be greater than zero"); - - return end_value (args(0), index_position-1, num_indices); - } - - // If m_indexed_object is undefined, then this use of 'end' is - // either appearing in a function call argument list or in an - // attempt to index an undefined symbol. There seems to be no - // reasonable way to provide a better error message. So just fail - // with an invalid use message. See bug #58830. - - if (m_indexed_object.is_undefined ()) - error ("invalid use of 'end': may only be used to index existing value"); - - octave_value expr_result; - - if (m_index_list.empty ()) - expr_result = m_indexed_object; - else - { - try - { - // When evaluating "end" with no arguments, we should have - // been called from the built-in Fend function that appears - // in the context of an argument list. Fend will be - // evaluated in its own stack frame. But we need to - // evaluate the partial expression that the special "end" - // token applies to in the calling stack frame. - - unwind_action act ([=] (std::size_t frm) - { - m_call_stack.restore_frame (frm); - }, m_call_stack.current_frame ()); - - std::size_t n = m_call_stack.find_current_user_frame (); - m_call_stack.goto_frame (n); - - // End is only valid inside argument lists used for - // indexing. The dispatch class is set by the function that - // evaluates the argument list. - - // Silently ignore extra output values. - - octave_value_list tmp - = m_indexed_object.subsref (m_index_type, m_index_list, 1); - - expr_result = tmp.length () ? tmp(0) : octave_value (); - - if (expr_result.is_cs_list ()) - err_indexed_cs_list (); - } - catch (const index_exception&) - { - error ("error evaluating partial expression for END"); - } - } - - if (expr_result.isobject ()) - { - // FIXME: is there a better way to lookup and execute a method - // that handles all the details like setting the dispatch class - // appropriately? - - std::string dispatch_class = expr_result.class_name (); - - symbol_table& symtab = m_interpreter.get_symbol_table (); - - octave_value meth = symtab.find_method ("end", dispatch_class); - - if (meth.is_defined ()) - return m_interpreter.feval - (meth, ovl (expr_result, m_index_position+1, m_num_indices), 1); - } - - return end_value (expr_result, m_index_position, m_num_indices); -} - -octave_value -tree_evaluator::PS4 (const octave_value_list& args, int nargout) -{ - return set_internal_variable (m_PS4, args, nargout, "PS4"); -} - -bool tree_evaluator::echo_this_file (const std::string& file, int type) const -{ - if ((type & m_echo) == ECHO_SCRIPTS) - { - // Asking about scripts and echo is enabled for them. - return true; - } - - if ((type & m_echo) == ECHO_FUNCTIONS) - { - // Asking about functions and echo is enabled for functions. - // Now, which ones? - - auto p = m_echo_files.find (file); - - if (m_echo & ECHO_ALL) - { - // Return true ulness echo was turned off for a specific - // file. - - return (p == m_echo_files.end () || p->second); - } - else - { - // Return true if echo is specifically enabled for this file. - - return p != m_echo_files.end () && p->second; - } - } - - return false; -} - -void tree_evaluator::echo_code (int line) -{ - std::string prefix = command_editor::decode_prompt_string (m_PS4); - - octave_function *curr_fcn = m_call_stack.current_function (); - - if (curr_fcn && curr_fcn->is_user_code ()) - { - octave_user_code *code = dynamic_cast (curr_fcn); - - int num_lines = line - m_echo_file_pos + 1; - - std::deque lines - = code->get_code_lines (m_echo_file_pos, num_lines); - - for (auto& elt : lines) - octave_stdout << prefix << elt << std::endl; - } -} - -// Decide if it's time to quit a for or while loop. -bool tree_evaluator::quit_loop_now (void) -{ - octave_quit (); - - // Maybe handle 'continue N' someday... - - if (m_continuing) - m_continuing--; - - bool quit = (m_returning || m_breaking || m_continuing); - - if (m_breaking) - m_breaking--; - - return quit; -} - -void tree_evaluator::bind_auto_fcn_vars (const string_vector& arg_names, - const Matrix& ignored_outputs, - int nargin, int nargout, - bool takes_varargs, - const octave_value_list& va_args) -{ - set_auto_fcn_var (stack_frame::ARG_NAMES, Cell (arg_names)); - set_auto_fcn_var (stack_frame::IGNORED, ignored_outputs); - set_auto_fcn_var (stack_frame::NARGIN, nargin); - set_auto_fcn_var (stack_frame::NARGOUT, nargout); - set_auto_fcn_var (stack_frame::SAVED_WARNING_STATES, octave_value ()); - - if (takes_varargs) - assign ("varargin", va_args.cell_value ()); -} - -std::string -tree_evaluator::check_autoload_file (const std::string& nm) const -{ - if (sys::env::absolute_pathname (nm)) - return nm; - - std::string full_name = nm; - - octave_user_code *fcn = m_call_stack.current_user_code (); - - bool found = false; - - if (fcn) - { - std::string fname = fcn->fcn_file_name (); - - if (! fname.empty ()) - { - fname = sys::env::make_absolute (fname); - fname = fname.substr (0, fname.find_last_of (sys::file_ops::dir_sep_str ()) + 1); - - sys::file_stat fs (fname + nm); - - if (fs.exists ()) - { - full_name = fname + nm; - found = true; - } - } - } - - if (! found) - warning_with_id ("Octave:autoload-relative-file-name", - "autoload: '%s' is not an absolute filename", - nm.c_str ()); - - return full_name; -} + + if (! found) + warning_with_id ("Octave:autoload-relative-file-name", + "autoload: '%s' is not an absolute filename", + nm.c_str ()); + + return full_name; + } DEFMETHOD (max_recursion_depth, interp, args, nargout, doc: /* -*- texinfo -*- diff -r c2a0e546aab1 -r 3b7852a822e8 liboctave/array/Array.h --- a/liboctave/array/Array.h Fri Dec 02 10:11:46 2022 -0500 +++ b/liboctave/array/Array.h Fri Dec 02 10:12:40 2022 -0500 @@ -663,12 +663,6 @@ OCTARRAY_OVERRIDABLE_FUNC_API const T * data (void) const { return m_slice_data; } -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - OCTAVE_DEPRECATED (7, "for read-only access, use 'data' method instead") - OCTARRAY_OVERRIDABLE_FUNC_API const T * fortran_vec (void) const - { return data (); } -#endif - OCTARRAY_API T * fortran_vec (void); OCTARRAY_OVERRIDABLE_FUNC_API bool is_shared (void) diff -r c2a0e546aab1 -r 3b7852a822e8 liboctave/array/DiagArray2.h --- a/liboctave/array/DiagArray2.h Fri Dec 02 10:11:46 2022 -0500 +++ b/liboctave/array/DiagArray2.h Fri Dec 02 10:12:40 2022 -0500 @@ -168,11 +168,6 @@ const T * data (void) const { return Array::data (); } -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - OCTAVE_DEPRECATED (7, "for read-only access, use 'data' method instead") - const T * fortran_vec (void) const { return Array::data (); } -#endif - T * fortran_vec (void) { return Array::fortran_vec (); } void print_info (std::ostream& os, const std::string& prefix) const diff -r c2a0e546aab1 -r 3b7852a822e8 liboctave/array/Range.cc --- a/liboctave/array/Range.cc Fri Dec 02 10:11:46 2022 -0500 +++ b/liboctave/array/Range.cc Fri Dec 02 10:12:40 2022 -0500 @@ -453,553 +453,3 @@ } OCTAVE_END_NAMESPACE(octave) - -bool -Range::all_elements_are_ints (void) const -{ - // If the base and increment are ints, the final value in the range will also - // be an integer, even if the limit is not. If there is one or fewer - // elements only the base needs to be an integer. - - return (! (octave::math::isnan (m_base) || octave::math::isnan (m_inc)) - && (octave::math::nint_big (m_base) == m_base || m_numel < 1) - && (octave::math::nint_big (m_inc) == m_inc || m_numel <= 1)); -} - -octave_idx_type -Range::nnz (void) const -{ - octave_idx_type retval = 0; - - if (! isempty ()) - { - if ((m_base > 0.0 && m_limit > 0.0) || (m_base < 0.0 && m_limit < 0.0)) - { - // All elements have the same sign, hence there are no zeros. - retval = m_numel; - } - else if (m_inc != 0.0) - { - if (m_base == 0.0 || m_limit == 0.0) - // Exactly one zero at beginning or end of range. - retval = m_numel - 1; - else if ((m_base / m_inc) != std::floor (m_base / m_inc)) - // Range crosses negative/positive without hitting zero. - retval = m_numel; - else - // Range crosses negative/positive and hits zero. - retval = m_numel - 1; - } - else - { - // All elements are equal (m_inc = 0) but not positive or negative, - // therefore all elements are zero. - retval = 0; - } - } - - return retval; -} - -Matrix -Range::matrix_value (void) const -{ - Matrix retval (1, m_numel); - - if (m_numel > 0) - { - // The first element must always be *exactly* the base. - // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment). - retval(0) = m_base; - - double b = m_base; - double increment = m_inc; - for (octave_idx_type i = 1; i < m_numel - 1; i++) - retval.xelem (i) = b + i * increment; - - retval.xelem (m_numel - 1) = m_limit; - } - - return retval; -} - -double -Range::checkelem (octave_idx_type i) const -{ - if (i < 0 || i >= m_numel) - octave::err_index_out_of_range (2, 2, i+1, m_numel, dims ()); - - if (i == 0) - return m_base; - else if (i < m_numel - 1) - return m_base + i * m_inc; - else - return m_limit; -} - -double -Range::checkelem (octave_idx_type i, octave_idx_type j) const -{ - // Ranges are *always* row vectors. - if (i != 0) - octave::err_index_out_of_range (1, 1, i+1, m_numel, dims ()); - - return checkelem (j); -} - -double -Range::elem (octave_idx_type i) const -{ - if (i == 0) - return m_base; - else if (i < m_numel - 1) - return m_base + i * m_inc; - else - return m_limit; -} - -Array -Range::index (const octave::idx_vector& idx) const -{ - Array retval; - - octave_idx_type n = m_numel; - - if (idx.is_colon ()) - { - retval = matrix_value ().reshape (dim_vector (m_numel, 1)); - } - else - { - if (idx.extent (n) != n) - octave::err_index_out_of_range (1, 1, idx.extent (n), n, dims ()); // throws - - dim_vector idx_dims = idx.orig_dimensions (); - octave_idx_type idx_len = idx.length (n); - - // taken from Array.cc. - if (n != 1 && idx_dims.isvector ()) - idx_dims = dim_vector (1, idx_len); - - retval.clear (idx_dims); - - // Loop over all values in IDX, executing the lambda expression - // for each index value. - - double *array = retval.fortran_vec (); - - idx.loop (n, [=, &array] (idx_vector i) - { - if (i == 0) - *array++ = m_base; - else if (i < m_numel - 1) - *array++ = m_base + i * m_inc; - else - *array++ = m_limit; - }); - } - - return retval; -} - -// NOTE: max and min only return useful values if numel > 0. -// do_minmax_body() in max.cc avoids calling Range::min/max if numel == 0. - -double -Range::min (void) const -{ - double retval = 0.0; - if (m_numel > 0) - { - if (m_inc > 0) - retval = m_base; - else - { - retval = m_base + (m_numel - 1) * m_inc; - - // Require '<=' test. See note in max (). - if (retval <= m_limit) - retval = m_limit; - } - - } - return retval; -} - -double -Range::max (void) const -{ - double retval = 0.0; - if (m_numel > 0) - { - if (m_inc > 0) - { - retval = m_base + (m_numel - 1) * m_inc; - - // On some machines (x86 with extended precision floating point - // arithmetic, for example) it is possible that we can overshoot the - // limit by approximately the machine precision even though we were - // very careful in our calculation of the number of elements. - // Therefore, we clip the result to the limit if it overshoots. - // The test also includes equality (>= m_limit) to have expressions - // such as -5:1:-0 result in a -0 endpoint. - if (retval >= m_limit) - retval = m_limit; - } - else - retval = m_base; - } - return retval; -} - -void -Range::sort_internal (bool ascending) -{ - if ((ascending && m_base > m_limit && m_inc < 0.0) - || (! ascending && m_base < m_limit && m_inc > 0.0)) - { - std::swap (m_base, m_limit); - m_inc = -m_inc; - } -} - -void -Range::sort_internal (Array& sidx, bool ascending) -{ - octave_idx_type nel = numel (); - - sidx.resize (dim_vector (1, nel)); - - octave_idx_type *psidx = sidx.fortran_vec (); - - bool reverse = false; - - if ((ascending && m_base > m_limit && m_inc < 0.0) - || (! ascending && m_base < m_limit && m_inc > 0.0)) - { - std::swap (m_base, m_limit); - m_inc = -m_inc; - reverse = true; - } - - octave_idx_type tmp = (reverse ? nel - 1 : 0); - octave_idx_type stp = (reverse ? -1 : 1); - - for (octave_idx_type i = 0; i < nel; i++, tmp += stp) - psidx[i] = tmp; -} - -Matrix -Range::diag (octave_idx_type k) const -{ - return matrix_value ().diag (k); -} - -Range -Range::sort (octave_idx_type dim, sortmode mode) const -{ - Range retval = *this; - - if (dim == 1) - { - if (mode == ASCENDING) - retval.sort_internal (true); - else if (mode == DESCENDING) - retval.sort_internal (false); - } - else if (dim != 0) - (*current_liboctave_error_handler) ("Range::sort: invalid dimension"); - - return retval; -} - -Range -Range::sort (Array& sidx, octave_idx_type dim, - sortmode mode) const -{ - Range retval = *this; - - if (dim == 1) - { - if (mode == ASCENDING) - retval.sort_internal (sidx, true); - else if (mode == DESCENDING) - retval.sort_internal (sidx, false); - } - else if (dim != 0) - (*current_liboctave_error_handler) ("Range::sort: invalid dimension"); - - return retval; -} - -sortmode -Range::issorted (sortmode mode) const -{ - if (m_numel > 1 && m_inc > 0) - mode = (mode == DESCENDING) ? UNSORTED : ASCENDING; - else if (m_numel > 1 && m_inc < 0) - mode = (mode == ASCENDING) ? UNSORTED : DESCENDING; - else - mode = (mode == UNSORTED) ? ASCENDING : mode; - - return mode; -} - -void -Range::set_base (double b) -{ - if (m_base != b) - { - m_base = b; - - init (); - } -} - -void -Range::set_limit (double l) -{ - if (m_limit != l) - { - m_limit = l; - - init (); - } -} - -void -Range::set_inc (double i) -{ - if (m_inc != i) - { - m_inc = i; - - init (); - } -} - -std::ostream& -operator << (std::ostream& os, const Range& a) -{ - double b = a.base (); - double increment = a.increment (); - octave_idx_type nel = a.numel (); - - if (nel > 1) - { - // First element must be the base *exactly* (e.g., -0). - os << b << ' '; - for (octave_idx_type i = 1; i < nel-1; i++) - os << b + i * increment << ' '; - } - - // Print out the last element exactly, rather than a calculated last element. - os << a.m_limit << "\n"; - - return os; -} - -std::istream& -operator >> (std::istream& is, Range& a) -{ - is >> a.m_base; - if (is) - { - double tmp_limit; - is >> tmp_limit; - - if (is) - is >> a.m_inc; - - // Clip the m_limit to the true limit, rebuild numel, clear cache - a.set_limit (tmp_limit); - } - - return is; -} - -// DEPRECATED in Octave 7. -Range operator - (const Range& r) -{ - return Range (-r.base (), -r.limit (), -r.increment (), r.numel ()); -} - -// DEPRECATED in Octave 7. -Range operator + (double x, const Range& r) -{ - return Range (x + r.base (), x + r.limit (), r.increment (), r.numel ()); -} - -// DEPRECATED in Octave 7. -Range operator + (const Range& r, double x) -{ - return Range (r.base () + x, r.limit () + x, r.increment (), r.numel ()); -} - -// DEPRECATED in Octave 7. -Range operator - (double x, const Range& r) -{ - return Range (x - r.base (), x - r.limit (), -r.increment (), r.numel ()); -} - -// DEPRECATED in Octave 7. -Range operator - (const Range& r, double x) -{ - return Range (r.base () - x, r.limit () - x, r.increment (), r.numel ()); -} - -// DEPRECATED in Octave 7. -Range operator * (double x, const Range& r) -{ - return Range (x * r.base (), x * r.limit (), x * r.increment (), r.numel ()); -} - -// DEPRECATED in Octave 7. -Range operator * (const Range& r, double x) -{ - return Range (r.base () * x, r.limit () * x, r.increment () * x, r.numel ()); -} - -// C See Knuth, Art Of Computer Programming, Vol. 1, Problem 1.2.4-5. -// C -// C===Tolerant FLOOR function. -// C -// C X - is given as a Double Precision argument to be operated on. -// C It is assumed that X is represented with M mantissa bits. -// C CT - is given as a Comparison Tolerance such that -// C 0.LT.CT.LE.3-SQRT(5)/2. If the relative difference between -// C X and A whole number is less than CT, then TFLOOR is -// C returned as this whole number. By treating the -// C floating-point numbers as a finite ordered set note that -// C the heuristic EPS=2.**(-(M-1)) and CT=3*EPS causes -// C arguments of TFLOOR/TCEIL to be treated as whole numbers -// C if they are exactly whole numbers or are immediately -// C adjacent to whole number representations. Since EPS, the -// C "distance" between floating-point numbers on the unit -// C interval, and M, the number of bits in X'S mantissa, exist -// C on every floating-point computer, TFLOOR/TCEIL are -// C consistently definable on every floating-point computer. -// C -// C For more information see the following references: -// C (1) P. E. Hagerty, "More On Fuzzy Floor And Ceiling," APL QUOTE -// C QUAD 8(4):20-24, June 1978. Note that TFLOOR=FL5. -// C (2) L. M. Breed, "Definitions For Fuzzy Floor And Ceiling", APL -// C QUOTE QUAD 8(3):16-23, March 1978. This paper cites FL1 through -// C FL5, the history of five years of evolutionary development of -// C FL5 - the seven lines of code below - by open collaboration -// C and corroboration of the mathematical-computing community. -// C -// C Penn State University Center for Academic Computing -// C H. D. Knoble - August, 1978. - -static inline double -tfloor (double x, double ct) -{ -// C---------FLOOR(X) is the largest integer algebraically less than -// C or equal to X; that is, the unfuzzy FLOOR function. - -// DINT (X) = X - DMOD (X, 1.0); -// FLOOR (X) = DINT (X) - DMOD (2.0 + DSIGN (1.0, X), 3.0); - -// C---------Hagerty's FL5 function follows... - - double q = 1.0; - - if (x < 0.0) - q = 1.0 - ct; - - double rmax = q / (2.0 - ct); - - double t1 = 1.0 + std::floor (x); - t1 = (ct / q) * (t1 < 0.0 ? -t1 : t1); - t1 = (rmax < t1 ? rmax : t1); - t1 = (ct > t1 ? ct : t1); - t1 = std::floor (x + t1); - - if (x <= 0.0 || (t1 - x) < rmax) - return t1; - else - return t1 - 1.0; -} - -static inline bool -teq (double u, double v, - double ct = 3.0 * std::numeric_limits::epsilon ()) -{ - double tu = std::abs (u); - double tv = std::abs (v); - - return std::abs (u - v) < ((tu > tv ? tu : tv) * ct); -} - -octave_idx_type -Range::numel_internal (void) const -{ - octave_idx_type retval = -1; - - if (! octave::math::isfinite (m_base) || ! octave::math::isfinite (m_inc) - || octave::math::isnan (m_limit)) - retval = -2; - else if (octave::math::isinf (m_limit) - && ((m_inc > 0 && m_limit > 0) - || (m_inc < 0 && m_limit < 0))) - retval = std::numeric_limits::max () - 1; - else if (m_inc == 0 - || (m_limit > m_base && m_inc < 0) - || (m_limit < m_base && m_inc > 0)) - { - retval = 0; - } - else - { - double ct = 3.0 * std::numeric_limits::epsilon (); - - double tmp = tfloor ((m_limit - m_base + m_inc) / m_inc, ct); - - octave_idx_type n_elt = (tmp > 0.0 - ? static_cast (tmp) : 0); - - // If the final element that we would compute for the range is equal to - // the limit of the range, or is an adjacent floating point number, - // accept it. Otherwise, try a range with one fewer element. If that - // fails, try again with one more element. - // - // I'm not sure this is very good, but it seems to work better than just - // using tfloor as above. For example, without it, the expression - // 1.8:0.05:1.9 fails to produce the expected result of [1.8, 1.85, 1.9]. - - if (! teq (m_base + (n_elt - 1) * m_inc, m_limit)) - { - if (teq (m_base + (n_elt - 2) * m_inc, m_limit)) - n_elt--; - else if (teq (m_base + n_elt * m_inc, m_limit)) - n_elt++; - } - - retval = ((n_elt < std::numeric_limits::max ()) - ? n_elt : -1); - } - - return retval; -} - -double -Range::limit_internal (void) const -{ - double new_limit = m_inc > 0 ? max () : min (); - - // If result must be an integer then force the new_limit to be one. - if (all_elements_are_ints ()) - new_limit = std::round (new_limit); - - return new_limit; -} - -void -Range::init (void) -{ - m_numel = numel_internal (); - - if (! octave::math::isinf (m_limit)) - m_limit = limit_internal (); -} diff -r c2a0e546aab1 -r 3b7852a822e8 liboctave/array/Range.h --- a/liboctave/array/Range.h Fri Dec 02 10:11:46 2022 -0500 +++ b/liboctave/array/Range.h Fri Dec 02 10:12:40 2022 -0500 @@ -40,550 +40,360 @@ OCTAVE_BEGIN_NAMESPACE(octave) -// For now, only define for floating point types. However, we only -// need range as a temporary local variable in make_float_range -// in ov.cc. - -template -class -range::value>::type> -{ -public: - - range (void) - : m_base (0), m_increment (0), m_limit (0), m_final (0), m_numel (0), - m_reverse (false) - { } - - // LIMIT is an upper limit and may be outside the range of actual - // values. For floating point ranges, we perform a tolerant check - // to attempt to capture limit in the set of values if it is "close" - // to the value of base + a multiple of the increment. - - range (const T& base, const T& increment, const T& limit, - bool reverse = false) - : m_base (base), m_increment (increment), m_limit (limit), - m_final (), m_numel (), m_reverse (reverse) - { - init (); - } - - range (const T& base, const T& limit) - : m_base (base), m_increment (1), m_limit (limit), m_final (), m_numel (), - m_reverse (false) - { - init (); - } + // For now, only define for floating point types. However, we only + // need range as a temporary local variable in make_float_range + // in ov.cc. - // Allow conversion from (presumably) properly constructed Range - // objects. The values of base, limit, increment, and numel must be - // consistent. - - // FIXME: Actually check that base, limit, increment, and numel are - // consistent? - - range (const T& base, const T& increment, const T& limit, - octave_idx_type numel, bool reverse = false) - : m_base (base), m_increment (increment), m_limit (limit), - m_final (limit), m_numel (numel), m_reverse (reverse) - { } - - // We don't use a constructor for this because it will conflict with - // range (base, limit, increment) when T is octave_idx_type. - - static range make_n_element_range (const T& base, const T& increment, - octave_idx_type numel, - bool reverse = false) - { - // We could just make this constructor public, but it allows - // inconsistent ranges to be constructed. And it is probably much - // clearer to see "make_n_element_range" instead of puzzling over the - // purpose of this strange constructor form. - - T final_val = (reverse ? base - (numel - 1) * increment - : base + (numel - 1) * increment); - - return range (base, increment, final_val, numel, reverse); - } - - range (const range& r) - : m_base (r.m_base), m_increment (r.m_increment), - m_limit (r.m_limit), m_final (r.m_final), - m_numel (r.m_numel), m_reverse (r.m_reverse) - { } - - range& operator = (const range& r) + template + class + range::value>::type> { - if (this != &r) - { - m_base = r.m_base; - m_increment = r.m_increment; - m_limit = r.m_limit; - m_final = r.m_final; - m_numel = r.m_numel; - m_reverse = r.m_reverse; - } + public: + + range (void) + : m_base (0), m_increment (0), m_limit (0), m_final (0), m_numel (0), + m_reverse (false) + { } + + // LIMIT is an upper limit and may be outside the range of actual + // values. For floating point ranges, we perform a tolerant check + // to attempt to capture limit in the set of values if it is "close" + // to the value of base + a multiple of the increment. - return *this; - } - - ~range (void) = default; + range (const T& base, const T& increment, const T& limit, + bool reverse = false) + : m_base (base), m_increment (increment), m_limit (limit), + m_final (), m_numel (), m_reverse (reverse) + { + init (); + } - T base (void) const { return m_base; } - T increment (void) const { return m_increment; } - T limit (void) const { return m_limit; } - bool reverse (void) const { return m_reverse; } + range (const T& base, const T& limit) + : m_base (base), m_increment (1), m_limit (limit), m_final (), m_numel (), + m_reverse (false) + { + init (); + } + + // Allow conversion from (presumably) properly constructed Range + // objects. The values of base, limit, increment, and numel must be + // consistent. - T final_value (void) const { return m_final; } + // FIXME: Actually check that base, limit, increment, and numel are + // consistent? - T min (void) const - { - return (m_numel > 0 - ? ((m_reverse ? m_increment > T (0) - : m_increment > T (0)) ? base () : final_value ()) - : T (0)); - } + range (const T& base, const T& increment, const T& limit, + octave_idx_type numel, bool reverse = false) + : m_base (base), m_increment (increment), m_limit (limit), + m_final (limit), m_numel (numel), m_reverse (reverse) + { } + + // We don't use a constructor for this because it will conflict with + // range (base, limit, increment) when T is octave_idx_type. - T max (void) const - { - return (m_numel > 0 - ? ((m_reverse ? m_increment < T (0) - : m_increment > T (0)) ? final_value () : base ()) - : T (0)); - } + static range make_n_element_range (const T& base, const T& increment, + octave_idx_type numel, + bool reverse = false) + { + // We could just make this constructor public, but it allows + // inconsistent ranges to be constructed. And it is probably much + // clearer to see "make_n_element_range" instead of puzzling over the + // purpose of this strange constructor form. - octave_idx_type numel (void) const { return m_numel; } + T final_val = (reverse ? base - (numel - 1) * increment + : base + (numel - 1) * increment); + + return range (base, increment, final_val, numel, reverse); + } + + range (const range& r) + : m_base (r.m_base), m_increment (r.m_increment), + m_limit (r.m_limit), m_final (r.m_final), + m_numel (r.m_numel), m_reverse (r.m_reverse) + { } - // To support things like "for i = 1:Inf; ...; end" that are - // required for Matlab compatibility, creation of a range object - // like 1:Inf is allowed with m_numel set to - // numeric_limits::max(). However, it is not - // possible to store these ranges. The following function allows - // us to easily distinguish ranges with an infinite number of - // elements. There are specializations for double and float. + range& operator = (const range& r) + { + if (this != &r) + { + m_base = r.m_base; + m_increment = r.m_increment; + m_limit = r.m_limit; + m_final = r.m_final; + m_numel = r.m_numel; + m_reverse = r.m_reverse; + } - bool is_storable (void) const { return true; } + return *this; + } + + ~range (void) = default; - dim_vector dims (void) const { return dim_vector (1, m_numel); } + T base (void) const { return m_base; } + T increment (void) const { return m_increment; } + T limit (void) const { return m_limit; } + bool reverse (void) const { return m_reverse; } - octave_idx_type rows (void) const { return 1; } + T final_value (void) const { return m_final; } - octave_idx_type cols (void) const { return numel (); } - octave_idx_type columns (void) const { return numel (); } + T min (void) const + { + return (m_numel > 0 + ? ((m_reverse ? m_increment > T (0) + : m_increment > T (0)) ? base () : final_value ()) + : T (0)); + } - bool isempty (void) const { return numel () == 0; } + T max (void) const + { + return (m_numel > 0 + ? ((m_reverse ? m_increment < T (0) + : m_increment > T (0)) ? final_value () : base ()) + : T (0)); + } - bool all_elements_are_ints (void) const { return true; } + octave_idx_type numel (void) const { return m_numel; } - sortmode issorted (sortmode mode = ASCENDING) const - { - if (m_numel > 1 && (m_reverse ? m_increment < T (0) - : m_increment > T (0))) - mode = ((mode == DESCENDING) ? UNSORTED : ASCENDING); - else if (m_numel > 1 && (m_reverse ? m_increment > T (0) - : m_increment < T (0))) - mode = ((mode == ASCENDING) ? UNSORTED : DESCENDING); - else - mode = ((mode == UNSORTED) ? ASCENDING : mode); + // To support things like "for i = 1:Inf; ...; end" that are + // required for Matlab compatibility, creation of a range object + // like 1:Inf is allowed with m_numel set to + // numeric_limits::max(). However, it is not + // possible to store these ranges. The following function allows + // us to easily distinguish ranges with an infinite number of + // elements. There are specializations for double and float. + + bool is_storable (void) const { return true; } + + dim_vector dims (void) const { return dim_vector (1, m_numel); } + + octave_idx_type rows (void) const { return 1; } + + octave_idx_type cols (void) const { return numel (); } + octave_idx_type columns (void) const { return numel (); } + + bool isempty (void) const { return numel () == 0; } + + bool all_elements_are_ints (void) const { return true; } - return mode; - } - - OCTAVE_API octave_idx_type nnz (void) const; + sortmode issorted (sortmode mode = ASCENDING) const + { + if (m_numel > 1 && (m_reverse ? m_increment < T (0) + : m_increment > T (0))) + mode = ((mode == DESCENDING) ? UNSORTED : ASCENDING); + else if (m_numel > 1 && (m_reverse ? m_increment > T (0) + : m_increment < T (0))) + mode = ((mode == ASCENDING) ? UNSORTED : DESCENDING); + else + mode = ((mode == UNSORTED) ? ASCENDING : mode); - // Support for single-index subscripting, without generating matrix cache. + return mode; + } + + OCTAVE_API octave_idx_type nnz (void) const; - T checkelem (octave_idx_type i) const - { - if (i < 0 || i >= m_numel) - err_index_out_of_range (2, 2, i+1, m_numel, dims ()); + // Support for single-index subscripting, without generating matrix cache. + + T checkelem (octave_idx_type i) const + { + if (i < 0 || i >= m_numel) + err_index_out_of_range (2, 2, i+1, m_numel, dims ()); - if (i == 0) - // Required for proper NaN handling. - return (m_numel == 1 ? final_value () : m_base); - else if (i < m_numel - 1) - return (m_reverse ? m_base + T (i) * m_increment - : m_base + T (i) * m_increment); - else - return final_value (); - } + if (i == 0) + // Required for proper NaN handling. + return (m_numel == 1 ? final_value () : m_base); + else if (i < m_numel - 1) + return (m_reverse ? m_base + T (i) * m_increment + : m_base + T (i) * m_increment); + else + return final_value (); + } - T checkelem (octave_idx_type i, octave_idx_type j) const - { - // Ranges are *always* row vectors. - if (i != 0) - err_index_out_of_range (1, 1, i+1, m_numel, dims ()); + T checkelem (octave_idx_type i, octave_idx_type j) const + { + // Ranges are *always* row vectors. + if (i != 0) + err_index_out_of_range (1, 1, i+1, m_numel, dims ()); - return checkelem (j); - } + return checkelem (j); + } - T elem (octave_idx_type i) const - { - if (i == 0) - // Required for proper NaN handling. - return (m_numel == 1 ? final_value () : m_base); - else if (i < m_numel - 1) - return (m_reverse ? m_base - T (i) * m_increment - : m_base + T (i) * m_increment); - else - return final_value (); - } + T elem (octave_idx_type i) const + { + if (i == 0) + // Required for proper NaN handling. + return (m_numel == 1 ? final_value () : m_base); + else if (i < m_numel - 1) + return (m_reverse ? m_base - T (i) * m_increment + : m_base + T (i) * m_increment); + else + return final_value (); + } - T elem (octave_idx_type /* i */, octave_idx_type j) const - { - return elem (j); - } + T elem (octave_idx_type /* i */, octave_idx_type j) const + { + return elem (j); + } - T operator () (octave_idx_type i) const - { - return elem (i); - } + T operator () (octave_idx_type i) const + { + return elem (i); + } - T operator () (octave_idx_type i, octave_idx_type j) const - { - return elem (i, j); - } + T operator () (octave_idx_type i, octave_idx_type j) const + { + return elem (i, j); + } - Array index (const idx_vector& idx) const - { - Array retval; + Array index (const idx_vector& idx) const + { + Array retval; - octave_idx_type n = m_numel; + octave_idx_type n = m_numel; - if (idx.is_colon ()) - { - retval = array_value ().reshape (dim_vector (m_numel, 1)); - } - else - { - if (idx.extent (n) != n) - err_index_out_of_range (1, 1, idx.extent (n), n, dims ()); + if (idx.is_colon ()) + { + retval = array_value ().reshape (dim_vector (m_numel, 1)); + } + else + { + if (idx.extent (n) != n) + err_index_out_of_range (1, 1, idx.extent (n), n, dims ()); - dim_vector idx_dims = idx.orig_dimensions (); - octave_idx_type idx_len = idx.length (n); + dim_vector idx_dims = idx.orig_dimensions (); + octave_idx_type idx_len = idx.length (n); - // taken from Array.cc. - if (n != 1 && idx_dims.isvector ()) - idx_dims = dim_vector (1, idx_len); + // taken from Array.cc. + if (n != 1 && idx_dims.isvector ()) + idx_dims = dim_vector (1, idx_len); - retval.clear (idx_dims); + retval.clear (idx_dims); - // Loop over all values in IDX, executing the lambda - // expression for each index value. + // Loop over all values in IDX, executing the lambda + // expression for each index value. - T *array = retval.fortran_vec (); + T *array = retval.fortran_vec (); - idx.loop (n, [=, &array] (octave_idx_type i) - { - if (i == 0) - // Required for proper NaN handling. - *array++ = (m_numel == 0 ? m_final : m_base); - else if (i < m_numel - 1) - *array++ = (m_reverse ? m_base - T (i) * m_increment - : m_base + T (i) * m_increment); - else - *array++ = m_final; - }); - } + idx.loop (n, [=, &array] (octave_idx_type i) + { + if (i == 0) + // Required for proper NaN handling. + *array++ = (m_numel == 0 ? m_final : m_base); + else if (i < m_numel - 1) + *array++ = (m_reverse ? m_base - T (i) * m_increment + : m_base + T (i) * m_increment); + else + *array++ = m_final; + }); + } - return retval; - } + return retval; + } - Array diag (octave_idx_type k) const - { - return array_value ().diag (k); - } + Array diag (octave_idx_type k) const + { + return array_value ().diag (k); + } - Array array_value (void) const - { - octave_idx_type nel = numel (); + Array array_value (void) const + { + octave_idx_type nel = numel (); - Array retval (dim_vector (1, nel)); + Array retval (dim_vector (1, nel)); - if (nel == 1) - // Required for proper NaN handling. - retval(0) = final_value (); - else if (nel > 1) - { - // The first element must always be *exactly* the base. - // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment). - retval(0) = m_base; + if (nel == 1) + // Required for proper NaN handling. + retval(0) = final_value (); + else if (nel > 1) + { + // The first element must always be *exactly* the base. + // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment). + retval(0) = m_base; - if (m_reverse) - for (octave_idx_type i = 1; i < nel - 1; i++) - retval.xelem (i) = m_base - i * m_increment; - else - for (octave_idx_type i = 1; i < nel - 1; i++) - retval.xelem (i) = m_base + i * m_increment; + if (m_reverse) + for (octave_idx_type i = 1; i < nel - 1; i++) + retval.xelem (i) = m_base - i * m_increment; + else + for (octave_idx_type i = 1; i < nel - 1; i++) + retval.xelem (i) = m_base + i * m_increment; - retval.xelem (nel - 1) = final_value (); - } + retval.xelem (nel - 1) = final_value (); + } - return retval; - } + return retval; + } -private: + private: - T m_base; - T m_increment; - T m_limit; - T m_final; - octave_idx_type m_numel; - bool m_reverse; + T m_base; + T m_increment; + T m_limit; + T m_final; + octave_idx_type m_numel; + bool m_reverse; - // Setting the number of elements to zero when the increment is zero - // is intentional and matches the behavior of Matlab's colon - // operator. + // Setting the number of elements to zero when the increment is zero + // is intentional and matches the behavior of Matlab's colon + // operator. - // These calculations are appropriate for integer ranges. There are - // specializations for double and float. + // These calculations are appropriate for integer ranges. There are + // specializations for double and float. - void init (void) - { - if (m_reverse) - { - m_numel = ((m_increment == T (0) - || (m_limit > m_base && m_increment > T (0)) - || (m_limit < m_base && m_increment < T (0))) - ? T (0) - : (m_base - m_limit - m_increment) / m_increment); + void init (void) + { + if (m_reverse) + { + m_numel = ((m_increment == T (0) + || (m_limit > m_base && m_increment > T (0)) + || (m_limit < m_base && m_increment < T (0))) + ? T (0) + : (m_base - m_limit - m_increment) / m_increment); - m_final = m_base - (m_numel - 1) * m_increment; - } - else - { - m_numel = ((m_increment == T (0) - || (m_limit > m_base && m_increment < T (0)) - || (m_limit < m_base && m_increment > T (0))) - ? T (0) - : (m_limit - m_base + m_increment) / m_increment); + m_final = m_base - (m_numel - 1) * m_increment; + } + else + { + m_numel = ((m_increment == T (0) + || (m_limit > m_base && m_increment < T (0)) + || (m_limit < m_base && m_increment > T (0))) + ? T (0) + : (m_limit - m_base + m_increment) / m_increment); - m_final = m_base + (m_numel - 1) * m_increment; - } - } -}; + m_final = m_base + (m_numel - 1) * m_increment; + } + } + }; -// Specializations defined externally. + // Specializations defined externally. -template <> OCTAVE_API bool range::all_elements_are_ints (void) const; -template <> OCTAVE_API bool range::all_elements_are_ints (void) const; + template <> OCTAVE_API bool range::all_elements_are_ints (void) const; + template <> OCTAVE_API bool range::all_elements_are_ints (void) const; -template <> OCTAVE_API void range::init (void); -template <> OCTAVE_API void range::init (void); + template <> OCTAVE_API void range::init (void); + template <> OCTAVE_API void range::init (void); -// For now, only define for floating point types. However, we only -// need range as a temporary local variable in make_float_range -// in ov.cc. + // For now, only define for floating point types. However, we only + // need range as a temporary local variable in make_float_range + // in ov.cc. #if 0 -template <> OCTAVE_API void range::init (void); -template <> OCTAVE_API void range::init (void); -template <> OCTAVE_API void range::init (void); -template <> OCTAVE_API void range::init (void); -template <> OCTAVE_API void range::init (void); -template <> OCTAVE_API void range::init (void); -template <> OCTAVE_API void range::init (void); -template <> OCTAVE_API void range::init (void); + template <> OCTAVE_API void range::init (void); + template <> OCTAVE_API void range::init (void); + template <> OCTAVE_API void range::init (void); + template <> OCTAVE_API void range::init (void); + template <> OCTAVE_API void range::init (void); + template <> OCTAVE_API void range::init (void); + template <> OCTAVE_API void range::init (void); + template <> OCTAVE_API void range::init (void); #endif -template <> OCTAVE_API bool range::is_storable (void) const; -template <> OCTAVE_API bool range::is_storable (void) const; + template <> OCTAVE_API bool range::is_storable (void) const; + template <> OCTAVE_API bool range::is_storable (void) const; -template <> OCTAVE_API octave_idx_type range::nnz (void) const; -template <> OCTAVE_API octave_idx_type range::nnz (void) const; + template <> OCTAVE_API octave_idx_type range::nnz (void) const; + template <> OCTAVE_API octave_idx_type range::nnz (void) const; OCTAVE_END_NAMESPACE(octave) -class -Range -{ -public: - - OCTAVE_DEPRECATED (7, "use the 'octave::range' class instead") - Range (void) - : m_base (0), m_limit (0), m_inc (0), m_numel (0) - { } - - // Assume range is already properly constructed, so just copy internal - // values. However, we set LIMIT to the computed final value because - // that mimics the behavior of the other Range class constructors that - // reset limit to the computed final value. - - OCTAVE_DEPRECATED (7, "use the 'octave::range' class instead") - Range (const octave::range& r) - : m_base (r.base ()), m_limit (r.final_value ()), m_inc (r.increment ()), - m_numel (r.numel ()) - { } - - Range (const Range& r) = default; - - Range& operator = (const Range& r) = default; - - ~Range (void) = default; - - OCTAVE_DEPRECATED (7, "use the 'octave::range' class instead") - Range (double b, double l) - : m_base (b), m_limit (l), m_inc (1), m_numel (numel_internal ()) - { - if (! octave::math::isinf (m_limit)) - m_limit = limit_internal (); - } - - OCTAVE_DEPRECATED (7, "use the 'octave::range' class instead") - Range (double b, double l, double i) - : m_base (b), m_limit (l), m_inc (i), m_numel (numel_internal ()) - { - if (! octave::math::isinf (m_limit)) - m_limit = limit_internal (); - } - - // NOTE: The following constructor may be deprecated and removed after - // the arithmetic operators are removed. - - // For operators' usage (to preserve element count) and to create - // constant row vectors (obsolete usage). - - OCTAVE_DEPRECATED (7, "use the 'octave::range' class instead") - Range (double b, double i, octave_idx_type n) - : m_base (b), m_limit (b + (n-1) * i), m_inc (i), m_numel (n) - { - if (! octave::math::isinf (m_limit)) - m_limit = limit_internal (); - } - - // The range has a finite number of elements. - bool ok (void) const - { - return (octave::math::isfinite (m_limit) - && (m_numel >= 0 || m_numel == -2)); - } - - double base (void) const { return m_base; } - double limit (void) const { return m_limit; } - double inc (void) const { return m_inc; } - double increment (void) const { return m_inc; } - - // We adjust the limit to be the final value, so return that. We - // could introduce a new variable to store the final value separately, - // but it seems like that would just add confusion. If we changed - // the meaning of the limit function, we would change the behavior of - // programs that expect limit to be the final value instead of the - // value of the limit when the range was created. This problem will - // be fixed with the new template range class. - double final_value (void) const { return m_limit; } - - octave_idx_type numel (void) const { return m_numel; } - - dim_vector dims (void) const { return dim_vector (1, m_numel); } - - octave_idx_type rows (void) const { return 1; } - - octave_idx_type cols (void) const { return numel (); } - octave_idx_type columns (void) const { return numel (); } - - bool isempty (void) const { return numel () == 0; } - - OCTAVE_API bool all_elements_are_ints (void) const; - - OCTAVE_API Matrix matrix_value (void) const; - - OCTAVE_API double min (void) const; - OCTAVE_API double max (void) const; - - OCTAVE_API void sort_internal (bool ascending = true); - OCTAVE_API void sort_internal (Array& sidx, bool ascending = true); - - OCTAVE_API Matrix diag (octave_idx_type k = 0) const; - - OCTAVE_API Range sort (octave_idx_type dim = 0, sortmode mode = ASCENDING) const; - OCTAVE_API Range sort (Array& sidx, octave_idx_type dim = 0, - sortmode mode = ASCENDING) const; - - OCTAVE_API sortmode issorted (sortmode mode = ASCENDING) const; - - OCTAVE_API octave_idx_type nnz (void) const; - - // Support for single-index subscripting, without generating matrix cache. - - OCTAVE_API double checkelem (octave_idx_type i) const; - OCTAVE_API double checkelem (octave_idx_type i, octave_idx_type j) const; - - OCTAVE_API double elem (octave_idx_type i) const; - double elem (octave_idx_type /* i */, octave_idx_type j) const - { return elem (j); } - - double operator () (octave_idx_type i) const { return elem (i); } - double operator () (octave_idx_type i, octave_idx_type j) const - { return elem (i, j); } - - OCTAVE_API Array index (const octave::idx_vector& i) const; - - OCTAVE_API void set_base (double b); - - OCTAVE_API void set_limit (double l); - - OCTAVE_API void set_inc (double i); - - friend OCTAVE_API std::ostream& operator << (std::ostream& os, - const Range& r); - friend OCTAVE_API std::istream& operator >> (std::istream& is, Range& r); - - friend OCTAVE_API Range operator - (const Range& r); - friend OCTAVE_API Range operator + (double x, const Range& r); - friend OCTAVE_API Range operator + (const Range& r, double x); - friend OCTAVE_API Range operator - (double x, const Range& r); - friend OCTAVE_API Range operator - (const Range& r, double x); - friend OCTAVE_API Range operator * (double x, const Range& r); - friend OCTAVE_API Range operator * (const Range& r, double x); - -private: - - double m_base; - double m_limit; - double m_inc; - - octave_idx_type m_numel; - - OCTAVE_API octave_idx_type numel_internal (void) const; - - OCTAVE_API double limit_internal (void) const; - - OCTAVE_API void init (void); - -protected: - - // NOTE: The following constructor may be removed when the arithmetic - // operators are removed. - - // For operators' usage (to allow all values to be set directly). - Range (double b, double l, double i, octave_idx_type n) - : m_base (b), m_limit (l), m_inc (i), m_numel (n) - { } -}; - -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) -OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable") -extern OCTAVE_API Range operator - (const Range& r); - -OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable") -extern OCTAVE_API Range operator + (double x, const Range& r); - -OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable") -extern OCTAVE_API Range operator + (const Range& r, double x); - -OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable") -extern OCTAVE_API Range operator - (double x, const Range& r); - -OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable") -extern OCTAVE_API Range operator - (const Range& r, double x); - -OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable") -extern OCTAVE_API Range operator * (double x, const Range& r); - -OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable") -extern OCTAVE_API Range operator * (const Range& r, double x); #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 liboctave/numeric/CollocWt.h --- a/liboctave/numeric/CollocWt.h Fri Dec 02 10:11:46 2022 -0500 +++ b/liboctave/numeric/CollocWt.h Fri Dec 02 10:12:40 2022 -0500 @@ -209,9 +209,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) -OCTAVE_DEPRECATED (7, "use 'octave::CollocWt' instead") -typedef octave::CollocWt CollocWt; #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 liboctave/numeric/oct-convn.h --- a/liboctave/numeric/oct-convn.h Fri Dec 02 10:11:46 2022 -0500 +++ b/liboctave/numeric/oct-convn.h Fri Dec 02 10:12:40 2022 -0500 @@ -158,152 +158,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline NDArray -convn (const NDArray& a, const NDArray& b, convn_type ct) -{ - return octave::convn (a, b, static_cast (ct)); -} - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline Matrix -convn (const Matrix& a, const Matrix& b, convn_type ct) -{ - return octave::convn (a, b, octave::convert_enum (ct)); -} - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline Matrix -convn (const Matrix& a, const ColumnVector& c, const RowVector& r, - convn_type ct) -{ - return octave::convn (a, c, r, octave::convert_enum (ct)); -} - -// double complex X double real - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline ComplexNDArray -convn (const ComplexNDArray& a, const NDArray& b, convn_type ct) -{ - return octave::convn (a, b, octave::convert_enum (ct)); -} - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline ComplexMatrix -convn (const ComplexMatrix& a, const Matrix& b, convn_type ct) -{ - return octave::convn (a, b, octave::convert_enum (ct)); -} - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline ComplexMatrix -convn (const ComplexMatrix& a, const ColumnVector& c, const RowVector& r, - convn_type ct) -{ - return octave::convn (a, c, r, octave::convert_enum (ct)); -} - -// double complex X double complex - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline ComplexNDArray -convn (const ComplexNDArray& a, const ComplexNDArray& b, convn_type ct) -{ - return octave::convn (a, b, octave::convert_enum (ct)); -} - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline ComplexMatrix -convn (const ComplexMatrix& a, const ComplexMatrix& b, convn_type ct) -{ - return octave::convn (a, b, octave::convert_enum (ct)); -} - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline ComplexMatrix -convn (const ComplexMatrix& a, const ComplexColumnVector& c, - const ComplexRowVector& r, convn_type ct) -{ - return octave::convn (a, c, r, octave::convert_enum (ct)); -} - -// float real X float real - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline FloatNDArray -convn (const FloatNDArray& a, const FloatNDArray& b, convn_type ct) -{ - return octave::convn (a, b, octave::convert_enum (ct)); -} - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline FloatMatrix -convn (const FloatMatrix& a, const FloatMatrix& b, convn_type ct) -{ - return octave::convn (a, b, octave::convert_enum (ct)); -} - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline FloatMatrix -convn (const FloatMatrix& a, const FloatColumnVector& c, - const FloatRowVector& r, convn_type ct) -{ - return octave::convn (a, c, r, octave::convert_enum (ct)); -} - -// float complex X float real - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline FloatComplexNDArray -convn (const FloatComplexNDArray& a, const FloatNDArray& b, - convn_type ct) -{ - return octave::convn (a, b, octave::convert_enum (ct)); -} - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline FloatComplexMatrix -convn (const FloatComplexMatrix& a, const FloatMatrix& b, - convn_type ct) -{ - return octave::convn (a, b, octave::convert_enum (ct)); -} - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline FloatComplexMatrix -convn (const FloatComplexMatrix& a, const FloatColumnVector& c, - const FloatRowVector& r, convn_type ct) -{ - return octave::convn (a, c, r, octave::convert_enum (ct)); -} - -// float complex X float complex - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline FloatComplexNDArray -convn (const FloatComplexNDArray& a, const FloatComplexNDArray& b, - convn_type ct) -{ - return octave::convn (a, b, octave::convert_enum (ct)); -} - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline FloatComplexMatrix -convn (const FloatComplexMatrix& a, const FloatComplexMatrix& b, - convn_type ct) -{ - return octave::convn (a, b, octave::convert_enum (ct)); -} - -OCTAVE_DEPRECATED (7, "use 'octave::convn' instead") -inline FloatComplexMatrix -convn (const FloatComplexMatrix& a, const FloatComplexColumnVector& c, - const FloatComplexRowVector& r, convn_type ct) -{ - return octave::convn (a, c, r, octave::convert_enum (ct)); -} #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 liboctave/numeric/oct-norm.cc --- a/liboctave/numeric/oct-norm.cc Fri Dec 02 10:11:46 2022 -0500 +++ b/liboctave/numeric/oct-norm.cc Fri Dec 02 10:12:40 2022 -0500 @@ -65,261 +65,261 @@ OCTAVE_BEGIN_NAMESPACE(octave) -// Theory: norm accumulator is an object that has an accum method able -// to handle both real and complex element, and a cast operator -// returning the intermediate norm. Reference: Higham, N. "Estimating -// the Matrix p-Norm." Numer. Math. 62, 539-555, 1992. + // Theory: norm accumulator is an object that has an accum method able + // to handle both real and complex element, and a cast operator + // returning the intermediate norm. Reference: Higham, N. "Estimating + // the Matrix p-Norm." Numer. Math. 62, 539-555, 1992. -// norm accumulator for the p-norm -template -class norm_accumulator_p -{ -public: - norm_accumulator_p () { } // we need this one for Array - norm_accumulator_p (R pp) : m_p(pp), m_scl(0), m_sum(1) { } + // norm accumulator for the p-norm + template + class norm_accumulator_p + { + public: + norm_accumulator_p () { } // we need this one for Array + norm_accumulator_p (R pp) : m_p(pp), m_scl(0), m_sum(1) { } - template - void accum (U val) - { - octave_quit (); - R t = std::abs (val); - if (m_scl == t) // we need this to handle Infs properly - m_sum += 1; - else if (m_scl < t) - { - m_sum *= std::pow (m_scl/t, m_p); + template + void accum (U val) + { + octave_quit (); + R t = std::abs (val); + if (m_scl == t) // we need this to handle Infs properly m_sum += 1; - m_scl = t; - } - else if (t != 0) - m_sum += std::pow (t/m_scl, m_p); - } + else if (m_scl < t) + { + m_sum *= std::pow (m_scl/t, m_p); + m_sum += 1; + m_scl = t; + } + else if (t != 0) + m_sum += std::pow (t/m_scl, m_p); + } + + operator R () { return m_scl * std::pow (m_sum, 1/m_p); } - operator R () { return m_scl * std::pow (m_sum, 1/m_p); } + private: + R m_p, m_scl, m_sum; + }; -private: - R m_p, m_scl, m_sum; -}; + // norm accumulator for the minus p-pseudonorm + template + class norm_accumulator_mp + { + public: + norm_accumulator_mp () { } // we need this one for Array + norm_accumulator_mp (R pp) : m_p(pp), m_scl(0), m_sum(1) { } -// norm accumulator for the minus p-pseudonorm -template -class norm_accumulator_mp -{ -public: - norm_accumulator_mp () { } // we need this one for Array - norm_accumulator_mp (R pp) : m_p(pp), m_scl(0), m_sum(1) { } + template + void accum (U val) + { + octave_quit (); + R t = 1 / std::abs (val); + if (m_scl == t) + m_sum += 1; + else if (m_scl < t) + { + m_sum *= std::pow (m_scl/t, m_p); + m_sum += 1; + m_scl = t; + } + else if (t != 0) + m_sum += std::pow (t/m_scl, m_p); + } - template - void accum (U val) + operator R () { return m_scl * std::pow (m_sum, -1/m_p); } + + private: + R m_p, m_scl, m_sum; + }; + + // norm accumulator for the 2-norm (euclidean) + template + class norm_accumulator_2 { - octave_quit (); - R t = 1 / std::abs (val); - if (m_scl == t) - m_sum += 1; - else if (m_scl < t) - { - m_sum *= std::pow (m_scl/t, m_p); + public: + norm_accumulator_2 () : m_scl(0), m_sum(1) { } + + void accum (R val) + { + R t = std::abs (val); + if (m_scl == t) m_sum += 1; - m_scl = t; - } - else if (t != 0) - m_sum += std::pow (t/m_scl, m_p); - } + else if (m_scl < t) + { + m_sum *= pow2 (m_scl/t); + m_sum += 1; + m_scl = t; + } + else if (t != 0) + m_sum += pow2 (t/m_scl); + } - operator R () { return m_scl * std::pow (m_sum, -1/m_p); } + void accum (std::complex val) + { + accum (val.real ()); + accum (val.imag ()); + } + + operator R () { return m_scl * std::sqrt (m_sum); } + + private: + static inline R pow2 (R x) { return x*x; } + + //-------- -private: - R m_p, m_scl, m_sum; -}; + R m_scl, m_sum; + }; -// norm accumulator for the 2-norm (euclidean) -template -class norm_accumulator_2 -{ -public: - norm_accumulator_2 () : m_scl(0), m_sum(1) { } + // norm accumulator for the 1-norm (city metric) + template + class norm_accumulator_1 + { + public: + norm_accumulator_1 () : m_sum (0) { } + template + void accum (U val) + { + m_sum += std::abs (val); + } - void accum (R val) + operator R () { return m_sum; } + + private: + R m_sum; + }; + + // norm accumulator for the inf-norm (max metric) + template + class norm_accumulator_inf { - R t = std::abs (val); - if (m_scl == t) - m_sum += 1; - else if (m_scl < t) - { - m_sum *= pow2 (m_scl/t); - m_sum += 1; - m_scl = t; - } - else if (t != 0) - m_sum += pow2 (t/m_scl); - } + public: + norm_accumulator_inf () : m_max (0) { } + template + void accum (U val) + { + if (math::isnan (val)) + m_max = numeric_limits::NaN (); + else + m_max = std::max (m_max, std::abs (val)); + } + + operator R () { return m_max; } - void accum (std::complex val) + private: + R m_max; + }; + + // norm accumulator for the -inf pseudonorm (min abs value) + template + class norm_accumulator_minf { - accum (val.real ()); - accum (val.imag ()); - } + public: + norm_accumulator_minf () : m_min (numeric_limits::Inf ()) { } + template + void accum (U val) + { + if (math::isnan (val)) + m_min = numeric_limits::NaN (); + else + m_min = std::min (m_min, std::abs (val)); + } - operator R () { return m_scl * std::sqrt (m_sum); } - -private: - static inline R pow2 (R x) { return x*x; } + operator R () { return m_min; } - //-------- - - R m_scl, m_sum; -}; + private: + R m_min; + }; -// norm accumulator for the 1-norm (city metric) -template -class norm_accumulator_1 -{ -public: - norm_accumulator_1 () : m_sum (0) { } - template - void accum (U val) + // norm accumulator for the 0-pseudonorm (hamming distance) + template + class norm_accumulator_0 { - m_sum += std::abs (val); + public: + norm_accumulator_0 () : m_num (0) { } + template + void accum (U val) + { + if (val != static_cast (0)) ++m_num; + } + + operator R () { return m_num; } + + private: + unsigned int m_num; + }; + + // OK, we're armed :) Now let's go for the fun + + template + inline void vector_norm (const Array& v, R& res, ACC acc) + { + for (octave_idx_type i = 0; i < v.numel (); i++) + acc.accum (v(i)); + + res = acc; } - operator R () { return m_sum; } - -private: - R m_sum; -}; + // dense versions + template + void column_norms (const MArray& m, MArray& res, ACC acc) + { + res = MArray (dim_vector (1, m.columns ())); + for (octave_idx_type j = 0; j < m.columns (); j++) + { + ACC accj = acc; + for (octave_idx_type i = 0; i < m.rows (); i++) + accj.accum (m(i, j)); -// norm accumulator for the inf-norm (max metric) -template -class norm_accumulator_inf -{ -public: - norm_accumulator_inf () : m_max (0) { } - template - void accum (U val) - { - if (math::isnan (val)) - m_max = numeric_limits::NaN (); - else - m_max = std::max (m_max, std::abs (val)); + res.xelem (j) = accj; + } } - operator R () { return m_max; } - -private: - R m_max; -}; - -// norm accumulator for the -inf pseudonorm (min abs value) -template -class norm_accumulator_minf -{ -public: - norm_accumulator_minf () : m_min (numeric_limits::Inf ()) { } - template - void accum (U val) + template + void row_norms (const MArray& m, MArray& res, ACC acc) { - if (math::isnan (val)) - m_min = numeric_limits::NaN (); - else - m_min = std::min (m_min, std::abs (val)); - } - - operator R () { return m_min; } + res = MArray (dim_vector (m.rows (), 1)); + std::vector acci (m.rows (), acc); + for (octave_idx_type j = 0; j < m.columns (); j++) + { + for (octave_idx_type i = 0; i < m.rows (); i++) + acci[i].accum (m(i, j)); + } -private: - R m_min; -}; - -// norm accumulator for the 0-pseudonorm (hamming distance) -template -class norm_accumulator_0 -{ -public: - norm_accumulator_0 () : m_num (0) { } - template - void accum (U val) - { - if (val != static_cast (0)) ++m_num; + for (octave_idx_type i = 0; i < m.rows (); i++) + res.xelem (i) = acci[i]; } - operator R () { return m_num; } - -private: - unsigned int m_num; -}; - -// OK, we're armed :) Now let's go for the fun - -template -inline void vector_norm (const Array& v, R& res, ACC acc) -{ - for (octave_idx_type i = 0; i < v.numel (); i++) - acc.accum (v(i)); + // sparse versions + template + void column_norms (const MSparse& m, MArray& res, ACC acc) + { + res = MArray (dim_vector (1, m.columns ())); + for (octave_idx_type j = 0; j < m.columns (); j++) + { + ACC accj = acc; + for (octave_idx_type k = m.cidx (j); k < m.cidx (j+1); k++) + accj.accum (m.data (k)); - res = acc; -} - -// dense versions -template -void column_norms (const MArray& m, MArray& res, ACC acc) -{ - res = MArray (dim_vector (1, m.columns ())); - for (octave_idx_type j = 0; j < m.columns (); j++) - { - ACC accj = acc; - for (octave_idx_type i = 0; i < m.rows (); i++) - accj.accum (m(i, j)); - - res.xelem (j) = accj; - } -} + res.xelem (j) = accj; + } + } -template -void row_norms (const MArray& m, MArray& res, ACC acc) -{ - res = MArray (dim_vector (m.rows (), 1)); - std::vector acci (m.rows (), acc); - for (octave_idx_type j = 0; j < m.columns (); j++) - { - for (octave_idx_type i = 0; i < m.rows (); i++) - acci[i].accum (m(i, j)); - } - - for (octave_idx_type i = 0; i < m.rows (); i++) - res.xelem (i) = acci[i]; -} + template + void row_norms (const MSparse& m, MArray& res, ACC acc) + { + res = MArray (dim_vector (m.rows (), 1)); + std::vector acci (m.rows (), acc); + for (octave_idx_type j = 0; j < m.columns (); j++) + { + for (octave_idx_type k = m.cidx (j); k < m.cidx (j+1); k++) + acci[m.ridx (k)].accum (m.data (k)); + } -// sparse versions -template -void column_norms (const MSparse& m, MArray& res, ACC acc) -{ - res = MArray (dim_vector (1, m.columns ())); - for (octave_idx_type j = 0; j < m.columns (); j++) - { - ACC accj = acc; - for (octave_idx_type k = m.cidx (j); k < m.cidx (j+1); k++) - accj.accum (m.data (k)); - - res.xelem (j) = accj; - } -} + for (octave_idx_type i = 0; i < m.rows (); i++) + res.xelem (i) = acci[i]; + } -template -void row_norms (const MSparse& m, MArray& res, ACC acc) -{ - res = MArray (dim_vector (m.rows (), 1)); - std::vector acci (m.rows (), acc); - for (octave_idx_type j = 0; j < m.columns (); j++) - { - for (octave_idx_type k = m.cidx (j); k < m.cidx (j+1); k++) - acci[m.ridx (k)].accum (m.data (k)); - } - - for (octave_idx_type i = 0; i < m.rows (); i++) - res.xelem (i) = acci[i]; -} - -// now the dispatchers + // now the dispatchers #define DEFINE_DISPATCHER(FCN_NAME, ARG_TYPE, RES_TYPE) \ template \ RES_TYPE FCN_NAME (const ARG_TYPE& v, R p) \ @@ -345,224 +345,216 @@ return res; \ } -DEFINE_DISPATCHER (vector_norm, MArray, R) -DEFINE_DISPATCHER (column_norms, MArray, MArray) -DEFINE_DISPATCHER (row_norms, MArray, MArray) -DEFINE_DISPATCHER (column_norms, MSparse, MArray) -DEFINE_DISPATCHER (row_norms, MSparse, MArray) + DEFINE_DISPATCHER (vector_norm, MArray, R) + DEFINE_DISPATCHER (column_norms, MArray, MArray) + DEFINE_DISPATCHER (row_norms, MArray, MArray) + DEFINE_DISPATCHER (column_norms, MSparse, MArray) + DEFINE_DISPATCHER (row_norms, MSparse, MArray) -// The approximate subproblem in Higham's method. Find lambda and mu such -// that norm ([lambda, mu], p) == 1 and norm (y*lambda + col*mu, p) is -// maximized. -// Real version. As in Higham's paper. -template -static void -higham_subp (const ColVectorT& y, const ColVectorT& col, - octave_idx_type nsamp, R p, R& lambda, R& mu) -{ - R nrm = 0; - for (octave_idx_type i = 0; i < nsamp; i++) - { - octave_quit (); - R fi = i * static_cast (M_PI) / nsamp; - R lambda1 = cos (fi); - R mu1 = sin (fi); - R lmnr = std::pow (std::pow (std::abs (lambda1), p) + - std::pow (std::abs (mu1), p), 1/p); - lambda1 /= lmnr; mu1 /= lmnr; - R nrm1 = vector_norm (lambda1 * y + mu1 * col, p); - if (nrm1 > nrm) - { - lambda = lambda1; - mu = mu1; - nrm = nrm1; - } - } -} + // The approximate subproblem in Higham's method. Find lambda and mu such + // that norm ([lambda, mu], p) == 1 and norm (y*lambda + col*mu, p) is + // maximized. + // Real version. As in Higham's paper. + template + static void + higham_subp (const ColVectorT& y, const ColVectorT& col, + octave_idx_type nsamp, R p, R& lambda, R& mu) + { + R nrm = 0; + for (octave_idx_type i = 0; i < nsamp; i++) + { + octave_quit (); + R fi = i * static_cast (M_PI) / nsamp; + R lambda1 = cos (fi); + R mu1 = sin (fi); + R lmnr = std::pow (std::pow (std::abs (lambda1), p) + + std::pow (std::abs (mu1), p), 1/p); + lambda1 /= lmnr; mu1 /= lmnr; + R nrm1 = vector_norm (lambda1 * y + mu1 * col, p); + if (nrm1 > nrm) + { + lambda = lambda1; + mu = mu1; + nrm = nrm1; + } + } + } -// Complex version. Higham's paper does not deal with complex case, so we -// use a simple extension. First, guess the magnitudes as in real version, -// then try to rotate lambda to improve further. -template -static void -higham_subp (const ColVectorT& y, const ColVectorT& col, - octave_idx_type nsamp, R p, - std::complex& lambda, std::complex& mu) -{ - typedef std::complex CR; - R nrm = 0; - lambda = 1.0; - CR lamcu = lambda / std::abs (lambda); - // Probe magnitudes - for (octave_idx_type i = 0; i < nsamp; i++) - { - octave_quit (); - R fi = i * static_cast (M_PI) / nsamp; - R lambda1 = cos (fi); - R mu1 = sin (fi); - R lmnr = std::pow (std::pow (std::abs (lambda1), p) + - std::pow (std::abs (mu1), p), 1/p); - lambda1 /= lmnr; mu1 /= lmnr; - R nrm1 = vector_norm (lambda1 * lamcu * y + mu1 * col, p); - if (nrm1 > nrm) - { - lambda = lambda1 * lamcu; - mu = mu1; - nrm = nrm1; - } - } - R lama = std::abs (lambda); - // Probe orientation - for (octave_idx_type i = 0; i < nsamp; i++) - { - octave_quit (); - R fi = i * static_cast (M_PI) / nsamp; - lamcu = CR (cos (fi), sin (fi)); - R nrm1 = vector_norm (lama * lamcu * y + mu * col, p); - if (nrm1 > nrm) - { - lambda = lama * lamcu; - nrm = nrm1; - } - } -} + // Complex version. Higham's paper does not deal with complex case, so we + // use a simple extension. First, guess the magnitudes as in real version, + // then try to rotate lambda to improve further. + template + static void + higham_subp (const ColVectorT& y, const ColVectorT& col, + octave_idx_type nsamp, R p, + std::complex& lambda, std::complex& mu) + { + typedef std::complex CR; + R nrm = 0; + lambda = 1.0; + CR lamcu = lambda / std::abs (lambda); + // Probe magnitudes + for (octave_idx_type i = 0; i < nsamp; i++) + { + octave_quit (); + R fi = i * static_cast (M_PI) / nsamp; + R lambda1 = cos (fi); + R mu1 = sin (fi); + R lmnr = std::pow (std::pow (std::abs (lambda1), p) + + std::pow (std::abs (mu1), p), 1/p); + lambda1 /= lmnr; mu1 /= lmnr; + R nrm1 = vector_norm (lambda1 * lamcu * y + mu1 * col, p); + if (nrm1 > nrm) + { + lambda = lambda1 * lamcu; + mu = mu1; + nrm = nrm1; + } + } + R lama = std::abs (lambda); + // Probe orientation + for (octave_idx_type i = 0; i < nsamp; i++) + { + octave_quit (); + R fi = i * static_cast (M_PI) / nsamp; + lamcu = CR (cos (fi), sin (fi)); + R nrm1 = vector_norm (lama * lamcu * y + mu * col, p); + if (nrm1 > nrm) + { + lambda = lama * lamcu; + nrm = nrm1; + } + } + } -// the p-dual element (should work for both real and complex) -template -inline T elem_dual_p (T x, R p) -{ - return math::signum (x) * std::pow (std::abs (x), p-1); -} + // the p-dual element (should work for both real and complex) + template + inline T elem_dual_p (T x, R p) + { + return math::signum (x) * std::pow (std::abs (x), p-1); + } -// the VectorT is used for vectors, but actually it has to be -// a Matrix type to allow all the operations. For instance SparseMatrix -// does not support multiplication with column/row vectors. -// the dual vector -template -VectorT dual_p (const VectorT& x, R p, R q) -{ - VectorT res (x.dims ()); - for (octave_idx_type i = 0; i < x.numel (); i++) - res.xelem (i) = elem_dual_p (x(i), p); - return res / vector_norm (res, q); -} + // the VectorT is used for vectors, but actually it has to be + // a Matrix type to allow all the operations. For instance SparseMatrix + // does not support multiplication with column/row vectors. + // the dual vector + template + VectorT dual_p (const VectorT& x, R p, R q) + { + VectorT res (x.dims ()); + for (octave_idx_type i = 0; i < x.numel (); i++) + res.xelem (i) = elem_dual_p (x(i), p); + return res / vector_norm (res, q); + } -// Higham's hybrid method -template -R higham (const MatrixT& m, R p, R tol, int maxiter, - VectorT& x) -{ - x.resize (m.columns (), 1); - // the OSE part - VectorT y(m.rows (), 1, 0), z(m.rows (), 1); - typedef typename VectorT::element_type RR; - RR lambda = 0; - RR mu = 1; - for (octave_idx_type k = 0; k < m.columns (); k++) - { - octave_quit (); - VectorT col (m.column (k)); - if (k > 0) - higham_subp (y, col, 4*k, p, lambda, mu); - for (octave_idx_type i = 0; i < k; i++) - x(i) *= lambda; - x(k) = mu; - y = lambda * y + mu * col; - } - - // the PM part - x = x / vector_norm (x, p); - R q = p/(p-1); + // Higham's hybrid method + template + R higham (const MatrixT& m, R p, R tol, int maxiter, + VectorT& x) + { + x.resize (m.columns (), 1); + // the OSE part + VectorT y(m.rows (), 1, 0), z(m.rows (), 1); + typedef typename VectorT::element_type RR; + RR lambda = 0; + RR mu = 1; + for (octave_idx_type k = 0; k < m.columns (); k++) + { + octave_quit (); + VectorT col (m.column (k)); + if (k > 0) + higham_subp (y, col, 4*k, p, lambda, mu); + for (octave_idx_type i = 0; i < k; i++) + x(i) *= lambda; + x(k) = mu; + y = lambda * y + mu * col; + } - R gamma = 0, gamma1; - int iter = 0; - while (iter < maxiter) - { - octave_quit (); - y = m*x; - gamma1 = gamma; - gamma = vector_norm (y, p); - z = dual_p (y, p, q); - z = z.hermitian (); - z = z * m; + // the PM part + x = x / vector_norm (x, p); + R q = p/(p-1); - if (iter > 0 && (vector_norm (z, q) <= gamma - || (gamma - gamma1) <= tol*gamma)) - break; + R gamma = 0, gamma1; + int iter = 0; + while (iter < maxiter) + { + octave_quit (); + y = m*x; + gamma1 = gamma; + gamma = vector_norm (y, p); + z = dual_p (y, p, q); + z = z.hermitian (); + z = z * m; - z = z.hermitian (); - x = dual_p (z, q, p); - iter++; - } + if (iter > 0 && (vector_norm (z, q) <= gamma + || (gamma - gamma1) <= tol*gamma)) + break; - return gamma; -} + z = z.hermitian (); + x = dual_p (z, q, p); + iter++; + } -// derive column vector and SVD types + return gamma; + } -static const char *p_less1_gripe = "xnorm: p must be >= 1"; + // derive column vector and SVD types -// Static constant to control the maximum number of iterations. 100 seems to -// be a good value. Eventually, we can provide a means to change this -// constant from Octave. -static int max_norm_iter = 100; + static const char *p_less1_gripe = "xnorm: p must be >= 1"; -// version with SVD for dense matrices -template -R svd_matrix_norm (const MatrixT& m, R p, VectorT) -{ - // NOTE: The octave:: namespace tags are needed for the following - // function calls until the deprecated inline functions are removed - // from oct-norm.h. + // Static constant to control the maximum number of iterations. 100 seems to + // be a good value. Eventually, we can provide a means to change this + // constant from Octave. + static int max_norm_iter = 100; - R res = 0; - if (p == 2) - { - math::svd fact (m, math::svd::Type::sigma_only); - res = fact.singular_values () (0, 0); - } - else if (p == 1) - res = octave::xcolnorms (m, static_cast (1)).max (); - else if (lo_ieee_isinf (p) && p > 1) - res = octave::xrownorms (m, static_cast (1)).max (); - else if (p > 1) - { - VectorT x; - const R sqrteps = std::sqrt (std::numeric_limits::epsilon ()); - res = higham (m, p, sqrteps, max_norm_iter, x); - } - else - (*current_liboctave_error_handler) ("%s", p_less1_gripe); - - return res; -} + // version with SVD for dense matrices + template + R svd_matrix_norm (const MatrixT& m, R p, VectorT) + { + R res = 0; + if (p == 2) + { + math::svd fact (m, math::svd::Type::sigma_only); + res = fact.singular_values () (0, 0); + } + else if (p == 1) + res = xcolnorms (m, static_cast (1)).max (); + else if (lo_ieee_isinf (p) && p > 1) + res = xrownorms (m, static_cast (1)).max (); + else if (p > 1) + { + VectorT x; + const R sqrteps = std::sqrt (std::numeric_limits::epsilon ()); + res = higham (m, p, sqrteps, max_norm_iter, x); + } + else + (*current_liboctave_error_handler) ("%s", p_less1_gripe); -// SVD-free version for sparse matrices -template -R matrix_norm (const MatrixT& m, R p, VectorT) -{ - // NOTE: The octave:: namespace tags are needed for the following - // function calls until the deprecated inline functions are removed - // from oct-norm.h. + return res; + } - R res = 0; - if (p == 1) - res = octave::xcolnorms (m, static_cast (1)).max (); - else if (lo_ieee_isinf (p) && p > 1) - res = octave::xrownorms (m, static_cast (1)).max (); - else if (p > 1) - { - VectorT x; - const R sqrteps = std::sqrt (std::numeric_limits::epsilon ()); - res = higham (m, p, sqrteps, max_norm_iter, x); - } - else - (*current_liboctave_error_handler) ("%s", p_less1_gripe); + // SVD-free version for sparse matrices + template + R matrix_norm (const MatrixT& m, R p, VectorT) + { + R res = 0; + if (p == 1) + res = xcolnorms (m, static_cast (1)).max (); + else if (lo_ieee_isinf (p) && p > 1) + res = xrownorms (m, static_cast (1)).max (); + else if (p > 1) + { + VectorT x; + const R sqrteps = std::sqrt (std::numeric_limits::epsilon ()); + res = higham (m, p, sqrteps, max_norm_iter, x); + } + else + (*current_liboctave_error_handler) ("%s", p_less1_gripe); - return res; -} + return res; + } -// and finally, here's what we've promised in the header file + // and finally, here's what we've promised in the header file #define DEFINE_XNORM_FCNS(PREFIX, RTYPE) \ RTYPE xnorm (const PREFIX##ColumnVector& x, RTYPE p) \ @@ -582,21 +574,21 @@ return vector_norm (x, static_cast (2)); \ } -DEFINE_XNORM_FCNS(, double) -DEFINE_XNORM_FCNS(Complex, double) -DEFINE_XNORM_FCNS(Float, float) -DEFINE_XNORM_FCNS(FloatComplex, float) + DEFINE_XNORM_FCNS(, double) + DEFINE_XNORM_FCNS(Complex, double) + DEFINE_XNORM_FCNS(Float, float) + DEFINE_XNORM_FCNS(FloatComplex, float) -// this is needed to avoid copying the sparse matrix for xfrobnorm -template -inline void array_norm_2 (const T *v, octave_idx_type n, R& res) -{ - norm_accumulator_2 acc; - for (octave_idx_type i = 0; i < n; i++) - acc.accum (v[i]); + // this is needed to avoid copying the sparse matrix for xfrobnorm + template + inline void array_norm_2 (const T *v, octave_idx_type n, R& res) + { + norm_accumulator_2 acc; + for (octave_idx_type i = 0; i < n; i++) + acc.accum (v[i]); - res = acc; -} + res = acc; + } #define DEFINE_XNORM_SPARSE_FCNS(PREFIX, RTYPE) \ RTYPE xnorm (const Sparse##PREFIX##Matrix& x, RTYPE p) \ @@ -610,8 +602,8 @@ return res; \ } -DEFINE_XNORM_SPARSE_FCNS(, double) -DEFINE_XNORM_SPARSE_FCNS(Complex, double) + DEFINE_XNORM_SPARSE_FCNS(, double) + DEFINE_XNORM_SPARSE_FCNS(Complex, double) #define DEFINE_COLROW_NORM_FCNS(PREFIX, RPREFIX, RTYPE) \ RPREFIX##RowVector \ @@ -625,12 +617,12 @@ return row_norms (m, p); \ } \ -DEFINE_COLROW_NORM_FCNS(,, double) -DEFINE_COLROW_NORM_FCNS(Complex,, double) -DEFINE_COLROW_NORM_FCNS(Float, Float, float) -DEFINE_COLROW_NORM_FCNS(FloatComplex, Float, float) + DEFINE_COLROW_NORM_FCNS(, , double) + DEFINE_COLROW_NORM_FCNS(Complex, , double) + DEFINE_COLROW_NORM_FCNS(Float, Float, float) + DEFINE_COLROW_NORM_FCNS(FloatComplex, Float, float) -DEFINE_COLROW_NORM_FCNS(Sparse,, double) -DEFINE_COLROW_NORM_FCNS(SparseComplex,, double) + DEFINE_COLROW_NORM_FCNS(Sparse, , double) + DEFINE_COLROW_NORM_FCNS(SparseComplex, , double) OCTAVE_END_NAMESPACE(octave) diff -r c2a0e546aab1 -r 3b7852a822e8 liboctave/numeric/oct-norm.h --- a/liboctave/numeric/oct-norm.h Fri Dec 02 10:11:46 2022 -0500 +++ b/liboctave/numeric/oct-norm.h Fri Dec 02 10:12:40 2022 -0500 @@ -32,14 +32,6 @@ #include "oct-cmplx.h" -// The remaining includes can be removed when the deprecated functions -// at the end of this file are removed. - -#include "dColVector.h" -#include "dRowVector.h" -#include "fColVector.h" -#include "fRowVector.h" - OCTAVE_BEGIN_NAMESPACE(octave) extern OCTAVE_API double xnorm (const ColumnVector&, double p = 2); @@ -88,198 +80,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) -OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead") -inline double xnorm (const ColumnVector& v, double p = 2) -{ - return octave::xnorm (v, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead") -inline double xnorm (const RowVector& v, double p = 2) -{ - return octave::xnorm (v, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead") -inline double xnorm (const Matrix& m, double p = 2) -{ - return octave::xnorm (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xfrobnorm' instead") -inline double xfrobnorm (const Matrix& m) -{ - return octave::xfrobnorm (m); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead") -inline double xnorm (const ComplexColumnVector& v, double p = 2) -{ - return octave::xnorm (v, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead") -inline double xnorm (const ComplexRowVector& v, double p = 2) -{ - return octave::xnorm (v, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead") -inline double xnorm (const ComplexMatrix& m, double p = 2) -{ - return octave::xnorm (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xfrobnorm' instead") -inline double xfrobnorm (const ComplexMatrix& m) -{ - return octave::xfrobnorm (m); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead") -inline float xnorm (const FloatColumnVector& v, float p = 2) -{ - return octave::xnorm (v, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead") -inline float xnorm (const FloatRowVector& v, float p = 2) -{ - return octave::xnorm (v, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead") -inline float xnorm (const FloatMatrix& m, float p = 2) -{ - return octave::xnorm (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xfrobnorm' instead") -inline float xfrobnorm (const FloatMatrix& m) -{ - return octave::xfrobnorm (m); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead") -inline float xnorm (const FloatComplexColumnVector& v, float p = 2) -{ - return octave::xnorm (v, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead") -inline float xnorm (const FloatComplexRowVector& v, float p = 2) -{ - return octave::xnorm (v, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead") -inline float xnorm (const FloatComplexMatrix& m, float p = 2) -{ - return octave::xnorm (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xfrobnorm' instead") -inline float xfrobnorm (const FloatComplexMatrix& m) -{ - return octave::xfrobnorm (m); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead") -inline double xnorm (const SparseMatrix& m, double p = 2) -{ - return octave::xnorm (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xfrobnorm' instead") -inline double xfrobnorm (const SparseMatrix& m) -{ - return octave::xfrobnorm (m); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead") -inline double xnorm (const SparseComplexMatrix& m, double p = 2) -{ - return octave::xnorm (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xfrobnorm' instead") -inline double xfrobnorm (const SparseComplexMatrix& m) -{ - return octave::xfrobnorm (m); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xcolnorms' instead") -inline RowVector xcolnorms (const Matrix& m, double p = 2) -{ - return octave::xcolnorms (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xrownorms' instead") -inline ColumnVector xrownorms (const Matrix& m, double p = 2) -{ - return octave::xrownorms (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xcolnorms' instead") -inline RowVector xcolnorms (const ComplexMatrix& m, double p = 2) -{ - return octave::xcolnorms (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xrownorms' instead") -inline ColumnVector xrownorms (const ComplexMatrix& m, double p = 2) -{ - return octave::xrownorms (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xcolnorms' instead") -inline FloatRowVector xcolnorms (const FloatMatrix& m, float p = 2) -{ - return octave::xcolnorms (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xrownorms' instead") -inline FloatColumnVector xrownorms (const FloatMatrix& m, float p = 2) -{ - return octave::xrownorms (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xcolnorms' instead") -inline FloatRowVector xcolnorms (const FloatComplexMatrix& m, float p = 2) -{ - return octave::xcolnorms (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xrownorms' instead") -inline FloatColumnVector xrownorms (const FloatComplexMatrix& m, float p = 2) -{ - return octave::xrownorms (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xcolnorms' instead") -inline RowVector xcolnorms (const SparseMatrix& m, double p = 2) -{ - return octave::xcolnorms (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xrownorms' instead") -inline ColumnVector xrownorms (const SparseMatrix& m, double p = 2) -{ - return octave::xrownorms (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xcolnorms' instead") -inline RowVector xcolnorms (const SparseComplexMatrix& m, double p = 2) -{ - return octave::xcolnorms (m, p); -} - -OCTAVE_DEPRECATED (7, "use 'octave::xrownorms' instead") -inline ColumnVector xrownorms (const SparseComplexMatrix& m, double p = 2) -{ - return octave::xrownorms (m, p); -} #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 liboctave/numeric/oct-spparms.h --- a/liboctave/numeric/oct-spparms.h Fri Dec 02 10:11:46 2022 -0500 +++ b/liboctave/numeric/oct-spparms.h Fri Dec 02 10:12:40 2022 -0500 @@ -116,9 +116,4 @@ OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) -OCTAVE_DEPRECATED (7, "use 'octave::sparse_params' instead") -typedef octave::sparse_params octave_sparse_params; #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 liboctave/util/lo-ieee.h --- a/liboctave/util/lo-ieee.h Fri Dec 02 10:11:46 2022 -0500 +++ b/liboctave/util/lo-ieee.h Fri Dec 02 10:12:40 2022 -0500 @@ -156,17 +156,4 @@ #endif -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) - -OCTAVE_DEPRECATED (7, "use '__lo_ieee_isfinite' instead") -inline int __lo_ieee_finite (double x) { return __lo_ieee_isfinite (x); } - -OCTAVE_DEPRECATED (7, "use '__lo_ieee_float_isfinite' instead") -inline int __lo_ieee_float_finite (float x) -{ return __lo_ieee_float_isfinite (x); } - -#define lo_ieee_finite(x) lo_ieee_isfinite(x) - #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 liboctave/util/lo-utils.cc --- a/liboctave/util/lo-utils.cc Fri Dec 02 10:11:46 2022 -0500 +++ b/liboctave/util/lo-utils.cc Fri Dec 02 10:12:40 2022 -0500 @@ -47,473 +47,479 @@ OCTAVE_BEGIN_NAMESPACE(octave) -bool is_int_or_inf_or_nan (double x) -{ - return math::isnan (x) || math::x_nint (x) == x; -} + bool is_int_or_inf_or_nan (double x) + { + return math::isnan (x) || math::x_nint (x) == x; + } + + bool too_large_for_float (double x) + { + return (math::isfinite (x) + && fabs (x) > std::numeric_limits::max ()); + } + + bool too_large_for_float (const Complex& x) + { + return (too_large_for_float (x.real ()) + || too_large_for_float (x.imag ())); + } + + bool is_int_or_inf_or_nan (float x) + { + return math::isnan (x) || math::x_nint (x) == x; + } -bool too_large_for_float (double x) -{ - return (math::isfinite (x) - && fabs (x) > std::numeric_limits::max ()); -} + // Save a string. + + char * strsave (const char *s) + { + if (! s) + return nullptr; -bool too_large_for_float (const Complex& x) -{ - return (too_large_for_float (x.real ()) - || too_large_for_float (x.imag ())); -} + int len = strlen (s); + char *tmp = new char [len+1]; + tmp = strcpy (tmp, s); + return tmp; + } + + std::string fgets (FILE *f) + { + bool eof; + return fgets (f, eof); + } + + std::string fgets (FILE *f, bool& eof) + { + eof = false; + + std::string retval; -bool is_int_or_inf_or_nan (float x) -{ - return math::isnan (x) || math::x_nint (x) == x; -} + int grow_size = 1024; + int max_size = grow_size; + + char *buf = static_cast (std::malloc (max_size)); + if (! buf) + (*current_liboctave_error_handler) ("octave_fgets: unable to malloc %d bytes", max_size); -// Save a string. + char *bufptr = buf; + int len = 0; -char * strsave (const char *s) -{ - if (! s) - return nullptr; + do + { + if (std::fgets (bufptr, grow_size, f)) + { + len = strlen (bufptr); - int len = strlen (s); - char *tmp = new char [len+1]; - tmp = strcpy (tmp, s); - return tmp; -} + if (len == grow_size - 1) + { + int tmp = bufptr - buf + grow_size - 1; + grow_size *= 2; + max_size += grow_size; + auto tmpbuf = static_cast (std::realloc (buf, max_size)); + if (! tmpbuf) + { + free (buf); + (*current_liboctave_error_handler) ("octave_fgets: unable to realloc %d bytes", max_size); + } + buf = tmpbuf; + bufptr = buf + tmp; -std::string fgets (FILE *f) -{ - bool eof; - return fgets (f, eof); -} + if (*(bufptr-1) == '\n') + { + *bufptr = '\0'; + retval = buf; + } + } + else if (bufptr[len-1] != '\n') + { + bufptr[len++] = '\n'; + bufptr[len] = '\0'; + retval = buf; + } + else + retval = buf; + } + else + { + if (len == 0) + { + eof = true; -std::string fgets (FILE *f, bool& eof) -{ - eof = false; + free (buf); + + buf = nullptr; + } + + break; + } + } + while (retval.empty ()); + + free (buf); + + octave_quit (); - std::string retval; + return retval; + } - int grow_size = 1024; - int max_size = grow_size; + std::string fgetl (FILE *f) + { + bool eof; + return fgetl (f, eof); + } + + std::string fgetl (FILE *f, bool& eof) + { + std::string retval = fgets (f, eof); + + if (! retval.empty () && retval.back () == '\n') + retval.pop_back (); - char *buf = static_cast (std::malloc (max_size)); - if (! buf) - (*current_liboctave_error_handler) ("octave_fgets: unable to malloc %d bytes", max_size); + return retval; + } + + template + T + read_value (std::istream& is) + { + T retval; + is >> retval; + return retval; + } - char *bufptr = buf; - int len = 0; + template OCTAVE_API bool read_value (std::istream& is); + template OCTAVE_API octave_int8 read_value (std::istream& is); + template OCTAVE_API octave_int16 read_value (std::istream& is); + template OCTAVE_API octave_int32 read_value (std::istream& is); + template OCTAVE_API octave_int64 read_value (std::istream& is); + template OCTAVE_API octave_uint8 read_value (std::istream& is); + template OCTAVE_API octave_uint16 read_value (std::istream& is); + template OCTAVE_API octave_uint32 read_value (std::istream& is); + template OCTAVE_API octave_uint64 read_value (std::istream& is); - do - { - if (std::fgets (bufptr, grow_size, f)) + // Note that the caller is responsible for repositioning the stream on + // failure. + + template + T + read_inf_nan_na (std::istream& is, char c0) + { + T val = 0.0; + + switch (c0) + { + case 'i': case 'I': { - len = strlen (bufptr); - - if (len == grow_size - 1) + char c1 = is.get (); + if (c1 == 'n' || c1 == 'N') { - int tmp = bufptr - buf + grow_size - 1; - grow_size *= 2; - max_size += grow_size; - auto tmpbuf = static_cast (std::realloc (buf, max_size)); - if (! tmpbuf) + char c2 = is.get (); + if (c2 == 'f' || c2 == 'F') { - free (buf); - (*current_liboctave_error_handler) ("octave_fgets: unable to realloc %d bytes", max_size); + val = std::numeric_limits::infinity (); + is.peek (); // Potentially set EOF bit } - buf = tmpbuf; - bufptr = buf + tmp; + else + is.setstate (std::ios::failbit); + } + else + is.setstate (std::ios::failbit); + } + break; - if (*(bufptr-1) == '\n') + case 'n': case 'N': + { + char c1 = is.get (); + if (c1 == 'a' || c1 == 'A') + { + char c2 = is.get (); + if (c2 == 'n' || c2 == 'N') { - *bufptr = '\0'; - retval = buf; + val = std::numeric_limits::quiet_NaN (); + is.peek (); // Potentially set EOF bit + } + else + { + val = numeric_limits::NA (); + if (c2 != std::istream::traits_type::eof ()) + is.putback (c2); + else + is.clear (is.rdstate () & ~std::ios::failbit); } } - else if (bufptr[len-1] != '\n') - { - bufptr[len++] = '\n'; - bufptr[len] = '\0'; - retval = buf; - } else - retval = buf; + is.setstate (std::ios::failbit); } - else + break; + + default: + (*current_liboctave_error_handler) + ("read_inf_nan_na: invalid character '%c'", c0); + } + + return val; + } + + // Read a double value. Discard any sign on NaN and NA. + + template + double + read_fp_value (std::istream& is) + { + T val = 0.0; + + // FIXME: resetting stream position is likely to fail unless we are + // reading from a file. + std::streampos pos = is.tellg (); + + is >> std::ws; // skip through whitespace and advance stream pointer + + bool neg = false; + char c1 = is.get (); + switch (c1) + { + case '-': + neg = true; + OCTAVE_FALLTHROUGH; + + case '+': { - if (len == 0) + char c2 = 0; + c2 = is.get (); + if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N') + val = read_inf_nan_na (is, c2); + else if (isspace (c2)) + is.setstate (std::ios::failbit); + else { - eof = true; - - free (buf); - - buf = nullptr; + is.putback (c2); + is >> val; } - break; + if (neg && ! math::isnan (val) && ! is.fail ()) + val = -val; } - } - while (retval.empty ()); - - free (buf); - - octave_quit (); - - return retval; -} + break; -std::string fgetl (FILE *f) -{ - bool eof; - return fgetl (f, eof); -} + case 'i': case 'I': + case 'n': case 'N': + val = read_inf_nan_na (is, c1); + break; -std::string fgetl (FILE *f, bool& eof) -{ - std::string retval = fgets (f, eof); - - if (! retval.empty () && retval.back () == '\n') - retval.pop_back (); - - return retval; -} + default: + is.putback (c1); + is >> val; + break; + } -template -T -read_value (std::istream& is) -{ - T retval; - is >> retval; - return retval; -} + std::ios::iostate status = is.rdstate (); + if (status & std::ios::failbit) + { + // Convert MAX_VAL returned by C++ streams for very large numbers to Inf + if (val == std::numeric_limits::max ()) + { + if (neg) + val = -std::numeric_limits::infinity (); + else + val = std::numeric_limits::infinity (); + is.clear (status & ~std::ios::failbit); + } + else + { + // True error. + // Reset stream to original position, clear eof bit, pass status on. + is.clear (); + is.seekg (pos); + is.setstate (status & ~std::ios_base::eofbit); + } + } -template OCTAVE_API bool read_value (std::istream& is); -template OCTAVE_API octave_int8 read_value (std::istream& is); -template OCTAVE_API octave_int16 read_value (std::istream& is); -template OCTAVE_API octave_int32 read_value (std::istream& is); -template OCTAVE_API octave_int64 read_value (std::istream& is); -template OCTAVE_API octave_uint8 read_value (std::istream& is); -template OCTAVE_API octave_uint16 read_value (std::istream& is); -template OCTAVE_API octave_uint32 read_value (std::istream& is); -template OCTAVE_API octave_uint64 read_value (std::istream& is); + return val; + } -// Note that the caller is responsible for repositioning the stream on -// failure. + template + std::complex + read_cx_fp_value (std::istream& is) + { + T re = 0.0; + T im = 0.0; -template -T -read_inf_nan_na (std::istream& is, char c0) -{ - T val = 0.0; + std::complex cx = 0.0; + + char ch = ' '; - switch (c0) - { - case 'i': case 'I': + while (isspace (ch)) + ch = is.get (); + + if (ch == '(') { - char c1 = is.get (); - if (c1 == 'n' || c1 == 'N') + re = read_value (is); + ch = is.get (); + + if (ch == ',') { - char c2 = is.get (); - if (c2 == 'f' || c2 == 'F') - val = std::numeric_limits::infinity (); + im = read_value (is); + ch = is.get (); + + if (ch == ')') + cx = std::complex (re, im); else is.setstate (std::ios::failbit); } - else - is.setstate (std::ios::failbit); - } - break; - - case 'n': case 'N': - { - char c1 = is.get (); - if (c1 == 'a' || c1 == 'A') - { - char c2 = is.get (); - if (c2 == 'n' || c2 == 'N') - val = std::numeric_limits::quiet_NaN (); - else - { - val = numeric_limits::NA (); - if (c2 != std::istream::traits_type::eof ()) - is.putback (c2); - else - is.clear (is.rdstate () & ~std::ios::failbit); - } - } + else if (ch == ')') + cx = re; else is.setstate (std::ios::failbit); } - break; - - default: - (*current_liboctave_error_handler) - ("read_inf_nan_na: invalid character '%c'", c0); - } - - return val; -} - -// Read a double value. Discard any sign on NaN and NA. - -template -double -read_fp_value (std::istream& is) -{ - T val = 0.0; - - // FIXME: resetting stream position is likely to fail unless we are - // reading from a file. - std::streampos pos = is.tellg (); - - char c1 = ' '; + else + { + is.putback (ch); + cx = read_value (is); + } - while (isspace (c1)) - c1 = is.get (); - - bool neg = false; - - switch (c1) - { - case '-': - neg = true; - OCTAVE_FALLTHROUGH; + return cx; + } - case '+': - { - char c2 = 0; - c2 = is.get (); - if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N') - val = read_inf_nan_na (is, c2); - else - { - is.putback (c2); - is >> val; - } + // FIXME: Could we use traits and enable_if to avoid duplication in the + // following specializations? - if (neg && ! is.fail ()) - val = -val; - } - break; + template <> OCTAVE_API double read_value (std::istream& is) + { + return read_fp_value (is); + } - case 'i': case 'I': - case 'n': case 'N': - val = read_inf_nan_na (is, c1); - break; + template <> OCTAVE_API Complex read_value (std::istream& is) + { + return read_cx_fp_value (is); + } - default: - is.putback (c1); - is >> val; - break; - } + template <> OCTAVE_API float read_value (std::istream& is) + { + return read_fp_value (is); + } - std::ios::iostate status = is.rdstate (); - if (status & std::ios::failbit) - { - // Convert MAX_VAL returned by C++ streams for very large numbers to Inf - if (val == std::numeric_limits::max ()) - { - if (neg) - val = -std::numeric_limits::infinity (); - else - val = std::numeric_limits::infinity (); - is.clear (status & ~std::ios::failbit); - } - else - { - // True error. Reset stream to original position and pass status on. - is.clear (); - is.seekg (pos); - is.setstate (status); - } - } - - return val; -} + template <> OCTAVE_API FloatComplex read_value (std::istream& is) + { + return read_cx_fp_value (is); + } -template -std::complex -read_cx_fp_value (std::istream& is) -{ - T re = 0.0; - T im = 0.0; - - std::complex cx = 0.0; - - char ch = ' '; - - while (isspace (ch)) - ch = is.get (); - - if (ch == '(') - { - re = read_value (is); - ch = is.get (); - - if (ch == ',') - { - im = read_value (is); - ch = is.get (); + template + void + write_value (std::ostream& os, const T& value) + { + os << value; + } - if (ch == ')') - cx = std::complex (re, im); - else - is.setstate (std::ios::failbit); - } - else if (ch == ')') - cx = re; - else - is.setstate (std::ios::failbit); - } - else - { - is.putback (ch); - cx = read_value (is); - } - - return cx; -} - -// FIXME: Could we use traits and enable_if to avoid duplication in the -// following specializations? + template OCTAVE_API void + write_value (std::ostream& os, const bool& value); + template OCTAVE_API void + write_value (std::ostream& os, const octave_int8& value); + template OCTAVE_API void + write_value (std::ostream& os, const octave_int16& value); + template OCTAVE_API void + write_value (std::ostream& os, const octave_int32& value); + template OCTAVE_API void + write_value (std::ostream& os, const octave_int64& value); + template OCTAVE_API void + write_value (std::ostream& os, const octave_uint8& value); + template OCTAVE_API void + write_value (std::ostream& os, const octave_uint16& value); + template OCTAVE_API void + write_value (std::ostream& os, const octave_uint32& value); + template OCTAVE_API void + write_value (std::ostream& os, const octave_uint64& value); -template <> OCTAVE_API double read_value (std::istream& is) -{ - return read_fp_value (is); -} - -template <> OCTAVE_API Complex read_value (std::istream& is) -{ - return read_cx_fp_value (is); -} + // Note: precision is supposed to be managed outside of this function by + // setting stream parameters. -template <> OCTAVE_API float read_value (std::istream& is) -{ - return read_fp_value (is); -} - -template <> OCTAVE_API FloatComplex read_value (std::istream& is) -{ - return read_cx_fp_value (is); -} - -template -void -write_value (std::ostream& os, const T& value) -{ - os << value; -} + template <> OCTAVE_API void + write_value (std::ostream& os, const double& value) + { + if (lo_ieee_is_NA (value)) + os << "NA"; + else if (lo_ieee_isnan (value)) + os << "NaN"; + else if (lo_ieee_isinf (value)) + os << (value < 0 ? "-Inf" : "Inf"); + else + os << value; + } -template OCTAVE_API void -write_value (std::ostream& os, const bool& value); -template OCTAVE_API void -write_value (std::ostream& os, const octave_int8& value); -template OCTAVE_API void -write_value (std::ostream& os, const octave_int16& value); -template OCTAVE_API void -write_value (std::ostream& os, const octave_int32& value); -template OCTAVE_API void -write_value (std::ostream& os, const octave_int64& value); -template OCTAVE_API void -write_value (std::ostream& os, const octave_uint8& value); -template OCTAVE_API void -write_value (std::ostream& os, const octave_uint16& value); -template OCTAVE_API void -write_value (std::ostream& os, const octave_uint32& value); -template OCTAVE_API void -write_value (std::ostream& os, const octave_uint64& value); + template <> OCTAVE_API void + write_value (std::ostream& os, const Complex& value) + { + os << '('; + write_value (os, real (value)); + os << ','; + write_value (os, imag (value)); + os << ')'; + } -// Note: precision is supposed to be managed outside of this function by -// setting stream parameters. - -template <> OCTAVE_API void -write_value (std::ostream& os, const double& value) -{ - if (lo_ieee_is_NA (value)) - os << "NA"; - else if (lo_ieee_isnan (value)) - os << "NaN"; - else if (lo_ieee_isinf (value)) - os << (value < 0 ? "-Inf" : "Inf"); - else - os << value; -} + // Note: precision is supposed to be managed outside of this function by + // setting stream parameters. -template <> OCTAVE_API void -write_value (std::ostream& os, const Complex& value) -{ - os << '('; - write_value (os, real (value)); - os << ','; - write_value (os, imag (value)); - os << ')'; -} - -// Note: precision is supposed to be managed outside of this function by -// setting stream parameters. + template <> OCTAVE_API void + write_value (std::ostream& os, const float& value) + { + if (lo_ieee_is_NA (value)) + os << "NA"; + else if (lo_ieee_isnan (value)) + os << "NaN"; + else if (lo_ieee_isinf (value)) + os << (value < 0 ? "-Inf" : "Inf"); + else + os << value; + } -template <> OCTAVE_API void -write_value (std::ostream& os, const float& value) -{ - if (lo_ieee_is_NA (value)) - os << "NA"; - else if (lo_ieee_isnan (value)) - os << "NaN"; - else if (lo_ieee_isinf (value)) - os << (value < 0 ? "-Inf" : "Inf"); - else - os << value; -} - -template <> OCTAVE_API void -write_value (std::ostream& os, const FloatComplex& value) -{ - os << '('; - write_value (os, real (value)); - os << ','; - write_value (os, imag (value)); - os << ')'; -} + template <> OCTAVE_API void + write_value (std::ostream& os, const FloatComplex& value) + { + os << '('; + write_value (os, real (value)); + os << ','; + write_value (os, imag (value)); + os << ')'; + } OCTAVE_BEGIN_NAMESPACE(math) -bool int_multiply_overflow (int a, int b, int *r) -{ - return octave_i_multiply_overflow_wrapper (a, b, r); -} + bool int_multiply_overflow (int a, int b, int *r) + { + return octave_i_multiply_overflow_wrapper (a, b, r); + } -bool int_multiply_overflow (long int a, long int b, long int *r) -{ - return octave_li_multiply_overflow_wrapper (a, b, r); -} + bool int_multiply_overflow (long int a, long int b, long int *r) + { + return octave_li_multiply_overflow_wrapper (a, b, r); + } #if defined (OCTAVE_HAVE_LONG_LONG_INT) -bool int_multiply_overflow (long long int a, long long int b, - long long int *r) -{ - return octave_lli_multiply_overflow_wrapper (a, b, r); -} + bool int_multiply_overflow (long long int a, long long int b, + long long int *r) + { + return octave_lli_multiply_overflow_wrapper (a, b, r); + } #endif -bool int_multiply_overflow (unsigned int a, unsigned int b, - unsigned int *r) -{ - return octave_ui_multiply_overflow_wrapper (a, b, r); -} + bool int_multiply_overflow (unsigned int a, unsigned int b, + unsigned int *r) + { + return octave_ui_multiply_overflow_wrapper (a, b, r); + } -bool int_multiply_overflow (unsigned long int a, unsigned long int b, - unsigned long int *r) -{ - return octave_uli_multiply_overflow_wrapper (a, b, r); -} + bool int_multiply_overflow (unsigned long int a, unsigned long int b, + unsigned long int *r) + { + return octave_uli_multiply_overflow_wrapper (a, b, r); + } #if defined (OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT) -bool int_multiply_overflow (unsigned long long int a, - unsigned long long int b, - unsigned long long int *r) -{ - return octave_ulli_multiply_overflow_wrapper (a, b, r); -} + bool int_multiply_overflow (unsigned long long int a, + unsigned long long int b, + unsigned long long int *r) + { + return octave_ulli_multiply_overflow_wrapper (a, b, r); + } #endif OCTAVE_END_NAMESPACE(math) diff -r c2a0e546aab1 -r 3b7852a822e8 liboctave/util/lo-utils.h --- a/liboctave/util/lo-utils.h Fri Dec 02 10:11:46 2022 -0500 +++ b/liboctave/util/lo-utils.h Fri Dec 02 10:12:40 2022 -0500 @@ -137,146 +137,4 @@ OCTAVE_END_NAMESPACE(math) OCTAVE_END_NAMESPACE(octave) -#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS) -template -OCTAVE_DEPRECATED (7, "use 'octave::any_all_test' instead") -bool -any_all_test (F fcn, const T *m, octave_idx_type len) -{ - return octave::any_all_test (fcn, m, len); -} - -OCTAVE_DEPRECATED (7, "use 'octave::is_int_or_inf_or_nan' instead") -inline bool xis_int_or_inf_or_nan (double x) -{ - return octave::is_int_or_inf_or_nan (x); -} - -template -OCTAVE_DEPRECATED (7, "use 'octave::is_one_or_zero' instead") -bool -xis_one_or_zero (const T& x) -{ - return octave::is_one_or_zero (x); -} - -template -OCTAVE_DEPRECATED (7, "use 'octave::is_zero' instead") -bool -xis_zero (const T& x) -{ - return octave::is_zero (x); -} - -OCTAVE_DEPRECATED (7, "use 'octave::' instead") -inline bool xtoo_large_for_float (double x) -{ - return octave::too_large_for_float (x); -} - -OCTAVE_DEPRECATED (7, "use 'octave::' instead") -inline bool xtoo_large_for_float (const Complex& x) -{ - return octave::too_large_for_float (x); -} - -OCTAVE_DEPRECATED (7, "use 'octave::' instead") -inline bool xis_int_or_inf_or_nan (float x) -{ - return octave::is_int_or_inf_or_nan (x); -} - -OCTAVE_DEPRECATED (7, "use 'octave::' instead") -inline bool xtoo_large_for_float (float x) -{ - return octave::too_large_for_float (x); -} - -OCTAVE_DEPRECATED (7, "use 'octave::strsave' instead") -inline char * strsave (const char *s) -{ - return octave::strsave (s); -} - -OCTAVE_DEPRECATED (7, "use 'octave::fgets' instead") -inline std::string octave_fgets (std::FILE *f) -{ - return octave::fgets (f); -} - -OCTAVE_DEPRECATED (7, "use 'octave::fgetl' instead") -inline std::string octave_fgetl (std::FILE *f) -{ - return octave::fgetl (f); -} - -OCTAVE_DEPRECATED (7, "use 'octave::fgets' instead") -inline std::string octave_fgets (std::FILE *f, bool& eof) -{ - return octave::fgets (f, eof); -} - -OCTAVE_DEPRECATED (7, "use 'octave::fgetl' instead") -inline std::string octave_fgetl (std::FILE *f, bool& eof) -{ - return octave::fgetl (f, eof); -} - -OCTAVE_DEPRECATED (7, "use 'octave::read_value' instead") -inline double -octave_read_double (std::istream& is) -{ - return octave::read_value (is); -} - -OCTAVE_DEPRECATED (7, "use 'octave::read_value' instead") -inline Complex -octave_read_complex (std::istream& is) -{ - return octave::read_value (is); -} - -OCTAVE_DEPRECATED (7, "use 'octave::read_value' instead") -inline float -octave_read_float (std::istream& is) -{ - return octave::read_value (is); -} - -OCTAVE_DEPRECATED (7, "use 'octave::read_value' instead") -inline FloatComplex -octave_read_float_complex (std::istream& is) -{ - return octave::read_value (is); -} - -OCTAVE_DEPRECATED (7, "use 'octave::write_value' instead") -inline void -octave_write_double (std::ostream& os, double value) -{ - octave::write_value (os, value); -} - -OCTAVE_DEPRECATED (7, "use 'octave::write_value' instead") -inline void -octave_write_complex (std::ostream& os, const Complex& value) -{ - octave::write_value (os, value); -} - -OCTAVE_DEPRECATED (7, "use 'octave::write_value' instead") -inline void -octave_write_float (std::ostream& os, float value) -{ - octave::write_value (os, value); -} - -OCTAVE_DEPRECATED (7, "use 'octave::write_value' instead") -inline void -octave_write_float_complex (std::ostream& os, const FloatComplex& value) -{ - octave::write_value (os, value); -} #endif - -#endif diff -r c2a0e546aab1 -r 3b7852a822e8 oct-conf-post-public.in.h --- a/oct-conf-post-public.in.h Fri Dec 02 10:11:46 2022 -0500 +++ b/oct-conf-post-public.in.h Fri Dec 02 10:12:40 2022 -0500 @@ -39,7 +39,7 @@ OCTAVE_ATTRIBUTE_NAME in place of vendor specific attribute mechanisms. As compilers evolve, the underlying implementation can be changed with the macro definitions below. FIXME: Update macros - to use C++ standard attribute syntax when Octave moves to C++ 2011 + to use C++ standard attribute syntax when Octave moves to C++ 2014 standard. */ #if defined (__GNUC__) diff -r c2a0e546aab1 -r 3b7852a822e8 scripts/deprecated/disable_diagonal_matrix.m --- a/scripts/deprecated/disable_diagonal_matrix.m Fri Dec 02 10:11:46 2022 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -######################################################################## -## -## Copyright (C) 2021-2022 The Octave Project Developers -## -## See the file COPYRIGHT.md in the top-level directory of this -## distribution or . -## -## 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 -## . -## -######################################################################## - -## -*- texinfo -*- -## @deftypefn {} {@var{val} =} disable_diagonal_matrix () -## @deftypefnx {} {@var{old_val} =} disable_diagonal_matrix (@var{new_val}) -## @deftypefnx {} {@var{old_val} =} disable_diagonal_matrix (@var{new_val}, "local") -## -## @code{disable_diagonal_matrix} is deprecated and will be removed in Octave -## version 9. Use @code{optimize_diagonal_matrix} instead. -## -## Query or set whether storing diagonal matrices in a special space-efficient -## format is disabled. -## -## The default value is false. If this option is set to true, Octave will -## store ranges as full matrices. -## -## When called from inside a function with the @qcode{"local"} option, the -## setting is changed locally for the function and any subroutines it calls. -## The original setting is restored when exiting the function. -## @seealso{disable_diagonal_matrix, disable_permutation_matrix} -## @end deftypefn - -## FIXME: DEPRECATED: Remove in version 9. - -function retval = disable_diagonal_matrix (varargin) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "disable_diagonal_matrix is obsolete and will be removed from a future version of Octave, please use optimize_diagonal_matrix instead\n"); - endif - - if (nargin == 0) - retval = ! optimize_diagonal_matrix (); - elseif (nargout == 0) - optimize_diagonal_matrix (! varargin{1}, varargin{2:end}); - else - retval = ! optimize_diagonal_matrix (! varargin{1}, varargin{2:end}); - endif - -endfunction diff -r c2a0e546aab1 -r 3b7852a822e8 scripts/deprecated/disable_permutation_matrix.m --- a/scripts/deprecated/disable_permutation_matrix.m Fri Dec 02 10:11:46 2022 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -######################################################################## -## -## Copyright (C) 2021-2022 The Octave Project Developers -## -## See the file COPYRIGHT.md in the top-level directory of this -## distribution or . -## -## 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 -## . -## -######################################################################## - -## -*- texinfo -*- -## @deftypefn {} {@var{val} =} disable_permutation_matrix () -## @deftypefnx {} {@var{old_val} =} disable_permutation_matrix (@var{new_val}) -## @deftypefnx {} {@var{old_val} =} disable_permutation_matrix (@var{new_val}, "local") -## -## @code{disable_permutation_matrix} is deprecated and will be removed in -## Octave version 9. Use @code{optimize_permutation_matrix} instead. -## -## Query or set whether storing permutation matrices in a special -## space-efficient format is disabled. -## -## The default value is false. If this option is set to true, Octave will -## store ranges as full matrices. -## -## When called from inside a function with the @qcode{"local"} option, the -## setting is changed locally for the function and any subroutines it calls. -## The original setting is restored when exiting the function. -## @seealso{disable_diagonal_matrix, disable_permutation_matrix} -## @end deftypefn - -## FIXME: DEPRECATED: Remove in version 9. - -function retval = disable_permutation_matrix (varargin) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "disable_permutation_matrix is obsolete and will be removed from a future version of Octave, please use optimize_permutation_matrix instead\n"); - endif - - if (nargin == 0) - retval = ! optimize_permutation_matrix (); - elseif (nargout == 0) - optimize_permutation_matrix (! varargin{1}, varargin{2:end}); - else - retval = ! optimize_permutation_matrix (! varargin{1}, varargin{2:end}); - endif - -endfunction diff -r c2a0e546aab1 -r 3b7852a822e8 scripts/deprecated/disable_range.m --- a/scripts/deprecated/disable_range.m Fri Dec 02 10:11:46 2022 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -######################################################################## -## -## Copyright (C) 2021-2022 The Octave Project Developers -## -## See the file COPYRIGHT.md in the top-level directory of this -## distribution or . -## -## 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 -## . -## -######################################################################## - -## -*- texinfo -*- -## @deftypefn {} {@var{val} =} disable_range () -## @deftypefnx {} {@var{old_val} =} disable_range (@var{new_val}) -## @deftypefnx {} {@var{old_val} =} disable_range (@var{new_val}, "local") -## -## @code{disable_range} is deprecated and will be removed in Octave version 9. -## Use @code{optimize_range} instead. -## -## Query or set whether storing ranges in a special space-efficient format is -## disabled. -## -## The default value is false. If this option is set to true, Octave will -## store ranges as full matrices. -## -## When called from inside a function with the @qcode{"local"} option, the -## setting is changed locally for the function and any subroutines it calls. -## The original setting is restored when exiting the function. -## @seealso{disable_diagonal_matrix, disable_permutation_matrix} -## @end deftypefn - -## FIXME: DEPRECATED: Remove in version 9. - -function retval = disable_range (varargin) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "disable_range is obsolete and will be removed from a future version of Octave, please use optimize_range instead\n"); - endif - - if (nargin == 0) - retval = ! optimize_range (); - elseif (nargout == 0) - optimize_range (! varargin{1}, varargin{2:end}); - else - retval = ! optimize_range (! varargin{1}, varargin{2:end}); - endif - -endfunction diff -r c2a0e546aab1 -r 3b7852a822e8 scripts/deprecated/module.mk --- a/scripts/deprecated/module.mk Fri Dec 02 10:11:46 2022 -0500 +++ b/scripts/deprecated/module.mk Fri Dec 02 10:12:40 2022 -0500 @@ -2,9 +2,6 @@ %canon_reldir%_FCN_FILES = \ %reldir%/.oct-config \ - %reldir%/disable_diagonal_matrix.m \ - %reldir%/disable_permutation_matrix.m \ - %reldir%/disable_range.m \ %reldir%/shift.m \ %reldir%/sparse_auto_mutate.m diff -r c2a0e546aab1 -r 3b7852a822e8 scripts/geometry/tsearchn.m --- a/scripts/geometry/tsearchn.m Fri Dec 02 10:11:46 2022 -0500 +++ b/scripts/geometry/tsearchn.m Fri Dec 02 10:12:40 2022 -0500 @@ -26,15 +26,17 @@ ## -*- texinfo -*- ## @deftypefn {} {@var{idx} =} tsearchn (@var{x}, @var{t}, @var{xi}) ## @deftypefnx {} {[@var{idx}, @var{p}] =} tsearchn (@var{x}, @var{t}, @var{xi}) -## Search for the enclosing Delaunay convex hull. +## Find the simplexes enclosing the given points. ## -## For @code{@var{t} = delaunayn (@var{x})}, finds the index in @var{t} -## containing the points @var{xi}. For points outside the convex hull, -## @var{idx} is NaN. +## @code{tsearchn} is typically used with @code{delaunayn}: +## @code{@var{t} = delaunayn (@var{x})} returns a set of simplexes @code{t}, +## then @code{tsearchn} returns the row index of @var{t} containing each point +## of @var{xi}. For points outside the convex hull, @var{idx} is NaN. ## -## If requested @code{tsearchn} also returns the Barycentric coordinates -## @var{p} of the enclosing triangles. -## @seealso{delaunay, delaunayn} +## If requested, @code{tsearchn} also returns the barycentric coordinates +## @var{p} of the enclosing simplexes. +## +## @seealso{delaunay, delaunayn, tsearch} ## @end deftypefn function [idx, p] = tsearchn (x, t, xi) @@ -43,57 +45,53 @@ print_usage (); endif + if (columns (x) != columns (xi)) + error ("tsearchn: number of columns of X and XI must match"); + endif + + if (max (t(:)) > rows (x)) + error ("tsearchn: triangulation T must not access points outside X"); + endif + + if (nargout <= 1 && columns (x) == 2) # pass to the faster tsearch.cc + idx = tsearch (x(:,1), x(:,2), t, xi(:,1), xi(:,2)); + return; + endif + nt = rows (t); [m, n] = size (x); mi = rows (xi); idx = NaN (mi, 1); p = NaN (mi, n + 1); - ni = [1:mi].'; - for i = 1 : nt - ## Only calculate the Barycentric coordinates for points that have not - ## already been found in a triangle. - b = cart2bary (x (t (i, :), :), xi(ni,:)); - ## Our points xi are in the current triangle if - ## (all (b >= 0) && all (b <= 1)). However as we impose that - ## sum (b,2) == 1 we only need to test all(b>=0). Note need to add - ## a small margin for rounding errors - intri = all (b >= -1e-12, 2); - idx(ni(intri)) = i; - p(ni(intri),:) = b(intri, :); - ni(intri) = []; - endfor + for i = 1 : nt # each simplex in turn -endfunction - -function Beta = cart2bary (T, P) + T = x(t(i, :), :); # T is the current simplex + P = xi(ni, :); # P is the set of points left to calculate - ## Conversion of Cartesian to Barycentric coordinates. - ## Given a reference simplex in N dimensions represented by an - ## N+1-by-N matrix, an arbitrary point P in Cartesian coordinates, - ## represented by an N-by-1 column vector can be written as - ## - ## P = Beta * T - ## - ## Where Beta is an N+1 vector of the barycentric coordinates. A criteria - ## on Beta is that - ## - ## sum (Beta) == 1 - ## - ## and therefore we can write the above as - ## - ## P - T(end, :) = Beta(1:end-1) * (T(1:end-1,:) - ones (N,1) * T(end,:)) - ## - ## and then we can solve for Beta as - ## - ## Beta(1:end-1) = (P - T(end,:)) / (T(1:end-1,:) - ones (N,1) * T(end,:)) - ## Beta(end) = sum (Beta) - ## - ## Note code below is generalized for multiple values of P, one per row. - [M, N] = size (P); - Beta = (P - ones (M,1) * T(end,:)) / (T(1:end-1,:) - ones (N,1) * T(end,:)); - Beta (:,end+1) = 1 - sum (Beta, 2); + ## Convert to barycentric coords: these are used to express a point P + ## as P = Beta * T + ## where T is a simplex. + ## + ## If 0 <= Beta <= 1, then the linear combination is also convex, + ## and the point P is inside the simplex T, otherwise it is outside. + ## Since the equation system is underdetermined, we apply the constraint + ## sum (Beta) == 1 to make it unique up to scaling. + ## + ## Note that the code below is vectorized over P, one point per row. + + b = (P - T(end,:)) / (T(1:end-1,:) - T(end,:)); + b(:, end+1) = 1 - sum (b, 2); + + ## The points xi are inside the current simplex if + ## (all (b >= 0) && all (b <= 1)). As sum (b,2) == 1, we only need to + ## test all(b>=0). + inside = all (b >= -1e-12, 2); # -1e-12 instead of 0 for rounding errors + idx(ni(inside)) = i; + p(ni(inside), :) = b(inside, :); + ni = ni(! inside); + endfor endfunction @@ -121,3 +119,10 @@ %! [idx, p] = tsearchn (x,tri,[1,1]); %! assert (idx, NaN); %! assert (p, [NaN, NaN, NaN]); + +## Test input validation +%!error tsearchn () +%!error tsearchn (1) +%!error tsearchn (1, 2) +%!error tsearchn ([1,2], 3, 4) +%!error tsearchn (1, 2, 3) diff -r c2a0e546aab1 -r 3b7852a822e8 scripts/linear-algebra/module.mk --- a/scripts/linear-algebra/module.mk Fri Dec 02 10:11:46 2022 -0500 +++ b/scripts/linear-algebra/module.mk Fri Dec 02 10:12:40 2022 -0500 @@ -35,6 +35,7 @@ %reldir%/rref.m \ %reldir%/subspace.m \ %reldir%/trace.m \ + %reldir%/tensorprod.m \ %reldir%/vech.m \ %reldir%/vecnorm.m diff -r c2a0e546aab1 -r 3b7852a822e8 scripts/linear-algebra/tensorprod.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/linear-algebra/tensorprod.m Fri Dec 02 10:12:40 2022 -0500 @@ -0,0 +1,437 @@ +######################################################################## +## +## Copyright (C) 2022 The Octave Project Developers +## +## See the file COPYRIGHT.md in the top-level directory of this +## distribution or . +## +## 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 +## . +## +######################################################################## + +## -*- texinfo -*- +## @deftypefn {} {@var{C} =} tensorprod (@var{A}, @var{B}, @var{dimA}, @var{dimB}) +## @deftypefnx {} {@var{C} =} tensorprod (@var{A}, @var{B}, @var{dim}) +## @deftypefnx {} {@var{C} =} tensorprod (@var{A}, @var{B}) +## @deftypefnx {} {@var{C} =} tensorprod (@var{A}, @var{B}, "all") +## @deftypefnx {} {@var{C} =} tensorprod (@var{A}, @var{B}, @dots{}, "NumDimensionsA", @var{value}) +## Compute the tensor product between numeric tensors @var{A} and @var{B}. +## +## The dimensions of @var{A} and @var{B} that are contracted are defined by +## @var{dimA} and @var{dimB}, respectively. @var{dimA} and @var{dimB} are +## scalars or equal length vectors that define the dimensions to match up. +## The matched dimensions of @var{A} and @var{B} must have equal lengths. +## +## When @var{dim} is used, it is equivalent to @var{dimA} = @var{dimB} = +## @var{dim}. +## +## When no dimensions are specified, @var{dimA} = @var{dimB} = []. This +## computes the outer product between @var{A} and @var{B}. +## +## Using the "all" option results in the inner product between @var{A} and +## @var{B}. This requires size(@var{A}) == size(@var{B}). +## +## Use the property-value pair with the property name "NumDimensionsA" when +## @var{A} has trailing singleton dimensions that should be transfered to +## @var{C}. The specified @var{value} should be the total number of +## dimensions of @var{A}. +## +## Matlab Compatibility: Octave does not currently support the "name=value" +## syntax for the "NumDimensionsA" parameter. +## +## @seealso{kron, dot, mtimes} +## @end deftypefn + +function C = tensorprod (A, B, varargin) + + ## FIXME: shortcut code paths could be added for trivial cases, such as if + ## either A or B are a scalars, null, identity tensors, etc. + + if (nargin < 2 || nargin > 6) + print_usage (); + endif + + ## Check that A and B are single or double + if (! isfloat (A)) + error ("tensorprod: A must be a single or double precision array"); + endif + + if (! isfloat (B)) + error ("tensorprod: B must be a single or double precision array"); + endif + + ## Check for misplaced NumDimensionsA property + if (nargin > 2) + if (strcmpi (varargin{end}, "NumDimensionsA")) + error (["tensorprod: a value for the NumDimensionsA property must ", ... + "be provided"]); + elseif (strcmpi ( strtok (inputname (nargin, false)), "NumDimensionsA")) + ## FIXME: Add support for keyword=value syntax + error (["tensorprod: NumDimensionsA=ndimsA syntax is not yet ", ... + "supported in Octave - provide the value as a ", ... + "property-value pair"]); + endif + endif + + ## Check for NumDimensionsA property + if (nargin > 3) + if (strcmpi (varargin{end - 1}, "NumDimensionsA")) + if (! (isnumeric (varargin{end}) && isscalar (varargin{end}))) + error (["tensorprod: value for NumDimensionsA must be a ", ... + "numeric scalar"]); + elseif (varargin{end} < 1 || rem (varargin{end}, 1) != 0) + error (["tensorprod: value for NumDimensionsA must be a ", ... + "positive integer"]); + endif + NumDimensionsA = varargin{end}; + endif + endif + + existNumDimensionsA = exist ("NumDimensionsA"); + ndimargs = nargin - 2 - 2 * existNumDimensionsA; + + ## Set dimA and dimB + if (ndimargs == 0) + ## Calling without dimension arguments + dimA = []; + dimB = []; + elseif (ndimargs == 1) + ## Calling with dim or "all" option + if (isnumeric (varargin{1})) + if (! (isvector (varargin{1}) || isnull (varargin{1}))) + error ("tensorprod: dim must be a numeric vector of integers or []"); + endif + ## Calling with dim + dimA = transpose ([varargin{1}(:)]); + elseif (ischar (varargin{1})) + if (strcmpi (varargin{1}, "all")) + if (! size_equal (A, B)) + error (["tensorprod: size of A and B must be identical when ", ... + "using the 'all' option"]); + endif + else + error ("tensorprod: unknown option '%s'", varargin{1}); + endif + ## Calling with "all" option + dimA = 1:ndims(A); + else + error (["tensorprod: third argument must be a numeric vector of ", ... + "integers, [], or 'all'"]); + endif + dimB = dimA; + elseif (ndimargs == 2) + ## Calling with dimA and dimB + if (! (isnumeric (varargin{1}) && (isvector (varargin{1}) || ... + isnull (varargin{1})))) + error("tensorprod: dimA must be a numeric vector of integers or []"); + endif + + if (! (isnumeric (varargin{2}) && (isvector (varargin{2}) || ... + isnull (varargin{2})))) + error ("tensorprod: dimB must be a numeric vector of integers or []"); + endif + + if (length (varargin{1}) != length (varargin{2})) + error (["tensorprod: an equal number of dimensions must be ", ... + "matched for A and B"]); + endif + dimA = transpose ([varargin{1}(:)]); + dimB = transpose ([varargin{2}(:)]); + else + ## Something is wrong - try to find the error + for i = 1:ndimargs + if (ischar (varargin{i})) + if (strcmpi (varargin{i}, "NumDimensionsA")) + error ("tensorprod: misplaced 'NumDimensionsA' option"); + elseif (strcmpi (varargin{i}, "all")) + error ("tensorprod: misplaced 'all' option"); + else + error ("tensorprod: unknown option '%s'", varargin{i}); + endif + elseif (! isnumeric (varargin{i})) + error (["tensorprod: optional arguments must be numeric vectors ", ... + "of integers, [], 'all', or 'NumDimensionsA'"]); + endif + endfor + error ("tensorprod: too many dimension inputs given"); + endif + + ## Check that dimensions are positive integers ([] will also pass) + if (any ([dimA < 1, dimB < 1, (rem (dimA, 1) != 0), (rem (dimB, 1) != 0)])) + error ("tensorprod: dimension(s) must be positive integer(s)"); + endif + + ## Check that the length of matched dimensions are equal + if (any (size (A, dimA) != size (B, dimB))) + error (["tensorprod: matched dimension(s) of A and B must have the ", ... + "same length(s)"]); + endif + + ## Find size and ndims of A and B + ndimsA = max ([ndims(A), max(dimA)]); + sizeA = size (A, 1:ndimsA); + ndimsB = max ([ndims(B), max(dimB)]); + sizeB = size (B, 1:ndimsB); + + ## Take NumDimensionsA property into account + if (existNumDimensionsA) + if (NumDimensionsA < ndimsA) + if (ndimargs == 1) + error (["tensorprod: highest dimension of dim must be less than ", ... + "or equal to NumDimensionsA"]); + elseif (ndimargs == 2) + error (["tensorprod: highest dimension of dimA must be less ", ... + "than or equal to NumDimensionsA"]); + else + error (["tensorprod: NumDimensionsA cannot be smaller than the ", ... + "number of dimensions of A"]); + endif + elseif (NumDimensionsA > ndimsA) + sizeA = [sizeA, ones(1, NumDimensionsA - ndimsA)]; + ndimsA = NumDimensionsA; + endif + endif + + ## Interchange the dimension to sum over the end of A and the front of B + ## Prepare for A + remainDimA = setdiff (1:ndimsA, dimA); # Dimensions of A to keep + newDimOrderA = [remainDimA, dimA]; # New dim order [to_keep, to_contract] + newSizeA = [prod(sizeA(remainDimA)), prod(sizeA(dimA))]; # Temp. 2D size for A + remainSizeA = sizeA(remainDimA); # Contrib. to size of C from remaining A dims + + ## Prepare for B (See comments for A. Note that in principle, + ## prod (sizeB (dimB)) should always be equal to prod (sizeA (dimA)). May + ## be able to optimize further here. + remainDimB = setdiff (1:ndimsB, dimB); + newDimOrderB = [remainDimB, dimB]; + newSizeB = [prod(sizeB(remainDimB)), prod(sizeB(dimB))]; + remainSizeB = sizeB(remainDimB); + + ## Do reshaping into 2D array + newA = reshape (permute (A, newDimOrderA), newSizeA); + newB = reshape (permute (B, newDimOrderB), newSizeB); + + ## Compute + C = newA * transpose (newB); + + ## If not an inner product, reshape back to tensor + if (! isscalar (C)) + C = reshape (C, [remainSizeA, remainSizeB]); + endif + +endfunction + + +%!assert (tensorprod (2, 3), 6) +%!assert (tensorprod (2, 3, 1), 6) +%!assert (tensorprod (2, 3, 2), 6) +%!assert (tensorprod (2, 3, 10), 6) +%!assert (tensorprod (2, 3, [1 2]), 6) +%!assert (tensorprod (2, 3, [1 10]), 6) +%!assert (tensorprod (2, 3, []), 6) +%!assert (tensorprod (2, 3, 2, 1), 6) +%!assert (tensorprod (2, 3, [], []), 6) + +%!shared v1, v2, M1, M2, T +%! v1 = [1, 2]; +%! M1 = [1, 2; 3, 4]; +%! M2 = [1, 2; 3, 4; 5, 6]; +%! T = cat (3, M2, M2); + +%!assert (tensorprod (3, v1), reshape ([3, 6], [1, 1, 1, 2])); +%!assert (tensorprod (v1, 3), [3, 6]); +%!assert (tensorprod (v1, v1, "all"), 5); +%!assert (tensorprod (v1, v1), reshape ([1, 2, 2, 4], [1, 2, 1, 2])); +%!assert (tensorprod (v1, v1, 1), [1, 2; 2, 4]); +%!assert (tensorprod (v1, v1, 2), 5); +%!assert (tensorprod (v1, v1, 3), reshape ([1, 2, 2, 4], [1, 2, 1, 2])); +%!assert (tensorprod (v1, v1, 5), reshape ([1, 2, 2, 4], [1, 2, 1, 1, 1, 2])); + +%!assert (tensorprod (M1, v1), cat (4, [1,2;3,4], [2,4;6,8])) +%!assert (tensorprod (M1, v1'), cat (3, [1,2;3,4], [2,4;6,8])) +%!assert (tensorprod (v1, M1), reshape ([1 2 3 6 2 4 4 8], [1,2,2,2])) +%!assert (tensorprod (v1', M1), reshape ([1 2 3 6 2 4 4 8], [2,1,2,2])) +%!assert (tensorprod (M1, v1', 2, 1), [5; 11]) +%!assert (tensorprod (M1, v1', 4, 4), cat(4, M1, 2*M1)) +%!assert (tensorprod (M1, v1', [1, 3]), [7; 10]) +%!assert (tensorprod (M1, v1', [1, 3], [1, 3]), [7; 10]) +%!assert (tensorprod (M1, v1', [2, 3], [1, 3]), [5; 11]) +%!assert (tensorprod (M1, v1', [2; 3], [1; 3]), [5; 11]) +%!assert (tensorprod (M1, v1', [2; 3], [1, 3]), [5; 11]) +%!assert (tensorprod (M1, v1', [2, 3], [1; 3]), [5; 11]) +%!assert (tensorprod (M1, v1', [], []), cat (3, M1, 2*M1)) +%!assert (tensorprod (M1, M1, "all"), 30) +%!assert (tensorprod (M1, M1, 1), [10, 14; 14, 20]) +%!assert (tensorprod (M1, M1, 2), [5, 11; 11, 25]) +%!assert (tensorprod (M1, M2, 2), [5, 11, 17; 11, 25, 39]) +%!assert (tensorprod (M1, M2, 1, 2), [7, 15, 23; 10, 22, 34]) +%!assert (tensorprod (M1, M2), reshape ([1,3,2,4,3,9,6,12,5,15,10,20,2,6,4, ... +%! 8,4,12,8,16,6,18,12,24], [2,2,3,2])) + +%!assert (tensorprod (T, M1), +%! reshape([1,3,5,2,4,6,1,3,5,2,4,6,3,9,15,6,12,18,3,9,15,6,12,18,2, ... +%! 6,10,4,8,12,2,6,10,4,8,12,4,12,20,8,16,24,4,12,20,8,16,24], +%! [3,2,2,2,2])) +%!assert (tensorprod (T, M1, 2), +%! cat (3, [5, 5; 11 11; 17, 17], [11, 11; 25, 25; 39, 39])) +%!assert (tensorprod (T, M2, 1), cat (3, [35, 35; 44, 44], [44, 44; 56, 56])) +%!assert (tensorprod (T, M2, 2), cat (3, [5, 5; 11, 11; 17, 17], +%! [11,11;25,25;39,39], [17, 17; 39, 39; 61, 61])) +%!assert (tensorprod (T, T, "all"), 182) +%!assert (tensorprod (T, T, 1), +%! reshape ([35,44,35,44,44,56,44,56,35,44,35,44,44,56,44,56], +%! [2,2,2,2])) +%!assert (tensorprod (T, T, 2), +%! reshape ([5,11,17,5,11,17,11,25,39,11,25,39,17,39,61,17,39,61,5, ... +%! 11,17,5,11,17,11,25,39,11,25,39,17,39,61,17,39,61], +%! [3,2,3,2])) +%!assert (tensorprod (T, T, 3), +%! reshape ([2,6,10,4,8,12,6,18,30,12,24,36,10,30,50,20,40,60,4,12, ... +%! 20,8,16,24,8,24,40,16,32,48,12,36,60,24,48,72], [3,2,3,2])); +%!assert (tensorprod (T, T, 10), +%! reshape ([1,3,5,2,4,6,1,3,5,2,4,6,3,9,15,6,12,18,3,9,15,6,12,18, ... +%! 5,15,25,10,20,30,5,15,25,10,20,30,2,6,10,4,8,12,2,6,10, ... +%! 4,8,12,4,12,20,8,16,24,4,12,20,8,16,24,6,18,30,12,24,36, ... +%! 6,18,30,12,24,36,1,3,5,2,4,6,1,3,5,2,4,6,3,9,15,6,12,18, ... +%! 3,9,15,6,12,18,5,15,25,10,20,30,5,15,25,10,20,30,2,6,10, ... +%! 4,8,12,2,6,10,4,8,12,4,12,20,8,16,24,4,12,20,8,16,24,6, ... +%! 18,30,12,24,36,6,18,30,12,24,36], +%! [3,2,2,1,1,1,1,1,1,3,2,2])) +%!assert (tensorprod (T, T, []), +%! reshape ([1,3,5,2,4,6,1,3,5,2,4,6,3,9,15,6,12,18,3,9,15,6,12,18, ... +%! 5,15,25,10,20,30,5,15,25,10,20,30,2,6,10,4,8,12,2,6,10, ... +%! 4,8,12,4,12,20,8,16,24,4,12,20,8,16,24,6,18,30,12,24,36, ... +%! 6,18,30,12,24,36,1,3,5,2,4,6,1,3,5,2,4,6,3,9,15,6,12,18, ... +%! 3,9,15,6,12,18,5,15,25,10,20,30,5,15,25,10,20,30,2,6,10, ... +%! 4,8,12,2,6,10,4,8,12,4,12,20,8,16,24,4,12,20,8,16,24,6, ... +%! 18,30,12,24,36,6,18,30,12,24,36], +%! [3,2,2,3,2,2])) +%!assert (tensorprod (T, T, 2, 3), +%! reshape ([3,7,11,3,7,11,9,21,33,9,21,33,15,35,55,15,35,55,6,14, ... +%! 22,6,14,22,12,28,44,12,28,44,18,42,66,18,42,66], +%! [3,2,3,2])) +%!assert (tensorprod (T, T(1:2, 1:2, :), [2, 3],[1, 3]), +%! [14, 20; 30, 44; 46, 68]) +%!assert (tensorprod (T, T(1:2, 1:2, :), [3, 2],[1, 3]), +%! [12, 18; 28, 42; 44, 66]) +%!assert (tensorprod (T, reshape (T, [2, 2, 3]), 2, 1), +%! reshape ([7,15,23,7,15,23,9,23,37,9,23,37,16,36,56,16,36,56,7,15, ... +%! 23,7,15,23,9,23,37,9,23,37,16,36,56,16,36,56], +%! [3,2,2,3])) +%!assert (tensorprod (T, T, [1, 3]), [70, 88; 88, 112]) +%!assert (tensorprod (T, T, [1, 3]), tensorprod (T, T, [3, 1])) +%!assert (tensorprod (T, reshape (T, [2, 2, 3]), [2, 3], [1, 2]), +%! [16, 23, 25; 38, 51, 59; 60, 79, 93]) + +## NumDimensionsA tests +%!assert (tensorprod (v1, v1, "NumDimensionsA", 2), +%! reshape ([1, 2, 2, 4], [1, 2, 1, 2])); +%!assert (tensorprod (v1, v1, "numdimensionsa", 2), +%! tensorprod (v1, v1, "NumDimensionsA", 2)); +%!assert (tensorprod (v1, v1, "NumDimensionsA", 3), +%! reshape ([1, 2, 2, 4], [1, 2, 1, 1, 2])); +%!assert (tensorprod (v1, v1, [], "NumDimensionsA", 3), +%! reshape ([1, 2, 2, 4], [1, 2, 1, 1, 2])); +%!assert (tensorprod (v1, v1, [], [], "NumDimensionsA", 3), +%! reshape ([1, 2, 2, 4], [1, 2, 1, 1, 2])); +%!assert (tensorprod (v1, v1, "all", "NumDimensionsA", 3), 5); +%!assert (tensorprod (M1, v1, 2, "NumDimensionsA", 2), [5; 11]); +%!assert (tensorprod (M1, v1, 2, "NumDimensionsA", 5), [5; 11]); +%!assert (tensorprod (M1, v1, [2, 3], "NumDimensionsA", 5), [5; 11]); +%!assert (tensorprod (M1, M2, "NumDimensionsA", 2), reshape ([1,3,2,4,3,9,6, ... +%! 12,5,15,10,20,2,6,4,8,4,12,8,16,6,18,12,24], [2,2,3,2])) +%!assert (tensorprod (M1, M2, "NumDimensionsA", 3), reshape ([1,3,2,4,3,9,6, ... +%! 12,5,15,10,20,2,6,4,8,4,12,8,16,6,18,12,24], [2,2,1,3,2])) +%!assert (tensorprod (T, T, 1, "NumDimensionsA", 3), +%! reshape ([35,44,35,44,44,56,44,56,35,44,35,44,44,56,44,56], +%! [2,2,2,2])) +%!assert (tensorprod (T, T, 3, "NumDimensionsA", 3), +%! reshape ([2,6,10,4,8,12,6,18,30,12,24,36,10,30,50,20,40,60,4,12, ... +%! 20,8,16,24, 8,24,40,16,32,48,12,36,60,24,48,72], +%! [3,2,3,2])) +%!assert (tensorprod (T, T, 1, "NumDimensionsA", 4), +%! reshape ([35,44,35,44,44,56,44,56,35,44,35,44,44,56,44,56], +%! [2,2,1,2,2])) +%!assert (tensorprod (T, T, 4, "NumDimensionsA", 4), +%! reshape ([1,3,5,2,4,6,1,3,5,2,4,6,3,9,15,6,12,18,3,9,15,6,12,18,5, ... +%! 15,25,10,20,30,5,15,25,10,20,30,2,6,10,4,8,12,2,6,10,4,8, ... +%! 12,4,12,20,8,16,24,4,12,20,8,16,24,6,18,30,12,24,36,6,18, ... +%! 30,12,24,36,1,3,5,2,4,6,1,3,5,2,4,6,3,9,15,6,12,18,3,9,15, ... +%! 6,12,18,5,15,25,10,20,30,5,15,25,10,20,30,2,6,10,4,8,12,2, ... +%! 6,10,4,8,12,4,12,20,8,16,24,4,12,20,8,16,24,6,18,30,12,24, ... +%! 36,6,18,30,12,24,36], +%! [3,2,2,3,2,2])) + +## Test empty inputs +%!assert (tensorprod ([], []), zeros (0, 0, 0, 0)) +%!assert (tensorprod ([], 1), []) +%!assert (tensorprod (1, []), zeros (1, 1, 0, 0)) +%!assert (tensorprod (zeros (0, 0, 0), zeros (0, 0, 0)), zeros (0, 0, 0, 0, 0, 0)) +%!assert (tensorprod ([], [], []), zeros (0, 0, 0, 0)) +%!assert (tensorprod ([], [], 1), []) +%!assert (tensorprod ([], [], 2), []) +%!assert (tensorprod ([], [], 3), zeros (0, 0, 0, 0)) +%!assert (tensorprod ([], [], 4), zeros (0, 0, 1, 0, 0)) +%!assert (tensorprod ([], [], 5), zeros (0, 0, 1, 1, 0, 0)) +%!assert (tensorprod ([], [], 3, "NumDimensionsA", 4), zeros (0, 0, 1, 0, 0)) +%!assert (tensorprod ([], [], 3, 4, "NumDimensionsA", 5), zeros (0, 0, 1, 1, 0, 0)) + +## Test input validation +%!error tensorprod () +%!error tensorprod (1) +%!error tensorprod (1,2,3,4,5,6,7) +%!error tensorprod ("foo", 1) +%!error tensorprod (1, "bar") +%!error tensorprod (int32(1), 1) +%!error tensorprod (1, int32(1)) +%!error tensorprod (1, 1, "foo") +%!error tensorprod (1, 1, 1, "foo", 1) +%!error tensorprod (1, 1, "foo", 1) +%!error tensorprod (1, 1, 1, "bar") +%!error tensorprod (1, 1, zeros(0,0,0), []) +%!error tensorprod (1, 1, [], zeros(0,0,0)) +%!error tensorprod (1, 1, zeros(0,0,0)) +%!error tensorprod (1, 1, 1, "all", 1) +%!error tensorprod (1, 1, "NumDimensionsA", 1, 1) +%!error tensorprod (1, 1, 1, {}, 1) +%!error tensorprod (ones (3, 4), ones (4, 3), 1) +%!error tensorprod (ones (3, 4), ones (4, 3), 1, 1) +%!error tensorprod (1, 1, 0) +%!error tensorprod (1, 1, -1) +%!error tensorprod (1, 1, 1.5) +%!error tensorprod (1, 1, NaN) +%!error tensorprod (1, 1, Inf) +%!error tensorprod (1, 1, {}) +%!error tensorprod (ones (3, 4), ones (4, 3), 1, [1, 2]) +%!error tensorprod (ones (3, 4), ones (4, 3), 1, []) +%!error tensorprod (ones (3, 4), ones (4, 3), [], [1, 2]) +%!error tensorprod (ones (3, 4), ones (4, 3), "all") +%!error tensorprod (1, 1, "NumDimensionsA") +%!error tensorprod (ones (2, 2, 2), 1, "NumDimensionsA", 2) +%!error tensorprod (1, 1, 5, "NumDimensionsA", 4) +%!error tensorprod (1, 1, 5, 5, "NumDimensionsA", 4) +%!error tensorprod (1, 1, NumDimensionsA=4) +%!error tensorprod (1, 1, numdimensionsa=4) +%!error tensorprod (1, 1, 2, 1, 1) +%!error tensorprod (1, 1, 2, 1, 1, 1) +%!error tensorprod (1, 1, 2, 1, "NumDimensionsA", "foo") +%!error tensorprod (1, 1, 2, 1, "NumDimensionsA", {}) +%!error tensorprod (1, 1, 2, 1, "NumDimensionsA", -1) +%!error tensorprod (1, 1, 2, 1, "NumDimensionsA", 0) +%!error tensorprod (1, 1, 2, 1, "NumDimensionsA", 1.5) +%!error tensorprod (1, 1, 2, 1, "NumDimensionsA", NaN) +%!error tensorprod (1, 1, 2, 1, "NumDimensionsA", Inf) diff -r c2a0e546aab1 -r 3b7852a822e8 scripts/plot/util/__pltopt__.m --- a/scripts/plot/util/__pltopt__.m Fri Dec 02 10:11:46 2022 -0500 +++ b/scripts/plot/util/__pltopt__.m Fri Dec 02 10:12:40 2022 -0500 @@ -158,12 +158,6 @@ topt = opt(1); n = 1; - if (any (topt == "0":"6")) - warning ("Octave:deprecated-option", ... - ["%s: using numbers to select line colors is deprecated. ", ... - "Use the corresponding color identifier instead."], caller); - endif - ## LineStyles if (strncmp (opt, "--", 2) || strncmp (opt, "-.", 2)) options.linestyle = opt(1:2); @@ -195,20 +189,19 @@ topt = "+"; endif options.marker = topt; - ## Numeric color specs are for backward compatibility. Don't document. - elseif (topt == "k" || topt == "0") + elseif (topt == "k") options.color = [0, 0, 0]; - elseif (topt == "r" || topt == "1") + elseif (topt == "r") if (strncmp (opt, "red", 3)) n = 3; endif options.color = [1, 0, 0]; - elseif (topt == "g" || topt == "2") + elseif (topt == "g") if (strncmp (opt, "green", 5)) n = 5; endif options.color = [0, 1, 0]; - elseif (topt == "b" || topt == "3") + elseif (topt == "b") if (strncmp (opt, "black", 5)) options.color = [0, 0, 0]; n = 5; @@ -223,17 +216,17 @@ n = 6; endif options.color = [1, 1, 0]; - elseif (topt == "m" || topt == "4") + elseif (topt == "m") if (strncmp (opt, "magenta", 7)) n = 7; endif options.color = [1, 0, 1]; - elseif (topt == "c" || topt == "5") + elseif (topt == "c") if (strncmp (opt, "cyan", 4)) n = 4; endif options.color = [0, 1, 1]; - elseif (topt == "w" || topt == "6") + elseif (topt == "w") if (strncmp (opt, "white", 5)) n = 5; endif diff -r c2a0e546aab1 -r 3b7852a822e8 scripts/plot/util/private/__print_parse_opts__.m --- a/scripts/plot/util/private/__print_parse_opts__.m Fri Dec 02 10:11:46 2022 -0500 +++ b/scripts/plot/util/private/__print_parse_opts__.m Fri Dec 02 10:12:40 2022 -0500 @@ -234,7 +234,7 @@ if (any (strcmp (unsupported, arg_st.devopt))) warning ('Octave:print:deprecated-format', - 'print: "%s" format is no more officially supported', ... + 'print: "%s" format is no longer officially supported', arg_st.devopt); endif diff -r c2a0e546aab1 -r 3b7852a822e8 scripts/strings/isstring.m --- a/scripts/strings/isstring.m Fri Dec 02 10:11:46 2022 -0500 +++ b/scripts/strings/isstring.m Fri Dec 02 10:12:40 2022 -0500 @@ -46,7 +46,7 @@ print_usage (); endif - tf = false; + tf = isa (s, 'string'); endfunction @@ -60,4 +60,3 @@ %!assert (isstring ({"b"}), false) %!error isstring () -%!error isstring ("a", "b") diff -r c2a0e546aab1 -r 3b7852a822e8 scripts/testfun/oruntests.m --- a/scripts/testfun/oruntests.m Fri Dec 02 10:11:46 2022 -0500 +++ b/scripts/testfun/oruntests.m Fri Dec 02 10:12:40 2022 -0500 @@ -71,29 +71,34 @@ no_tests = {}; printf ("Processing files in %s:\n\n", directory); fflush (stdout); - for i = 1:numel (flist) - f = flist{i}; - if ((length (f) > 2 && strcmpi (f((end-1):end), ".m")) - || (length (f) > 3 && strcmpi (f((end-2):end), ".cc"))) - ff = fullfile (directory, f); - if (! isfile (ff)) - continue; + unwind_protect + old_dir = cd (directory); + for i = 1:numel (flist) + f = flist{i}; + if ((length (f) > 2 && strcmpi (f((end-1):end), ".m")) + || (length (f) > 3 && strcmpi (f((end-2):end), ".cc"))) + ff = fullfile (directory, f); + if (! isfile (ff)) + continue; + endif + if (has_tests (ff)) + print_test_file_name (f); + [p, n, xf, xb, sk, rtsk, rgrs] = test (ff, "quiet"); + print_pass_fail (p, n, xf, xb, sk, rtsk, rgrs); + fflush (stdout); + elseif (has_functions (ff)) + no_tests(end+1) = f; + endif + elseif (f(1) == "@") + f = fullfile (directory, f); + if (isfolder (f)) + dirs(end+1) = f; + endif endif - if (has_tests (ff)) - print_test_file_name (f); - [p, n, xf, xb, sk, rtsk, rgrs] = test (ff, "quiet"); - print_pass_fail (p, n, xf, xb, sk, rtsk, rgrs); - fflush (stdout); - elseif (has_functions (ff)) - no_tests(end+1) = f; - endif - elseif (f(1) == "@") - f = fullfile (directory, f); - if (isfolder (f)) - dirs(end+1) = f; - endif - endif - endfor + endfor + unwind_protect_cleanup + cd (old_dir); + end_unwind_protect if (! isempty (no_tests)) printf ("\nThe following files in %s have no tests:\n\n", directory); printf ("%s", list_in_columns (no_tests)); diff -r c2a0e546aab1 -r 3b7852a822e8 src/mkoctfile.in.cc --- a/src/mkoctfile.in.cc Fri Dec 02 10:11:46 2022 -0500 +++ b/src/mkoctfile.in.cc Fri Dec 02 10:12:40 2022 -0500 @@ -356,11 +356,6 @@ vars["LD_STATIC_FLAG"] = get_variable ("LD_STATIC_FLAG", %OCTAVE_CONF_LD_STATIC_FLAG%); - // FIXME: Remove LFLAGS in Octave 9 - vars["LFLAGS"] = get_variable ("LFLAGS", DEFAULT_LDFLAGS); - if (vars["LFLAGS"] != DEFAULT_LDFLAGS) - std::cerr << "mkoctfile: warning: LFLAGS is deprecated and will be removed in a future version of Octave, use LDFLAGS instead" << std::endl; - vars["F77_INTEGER8_FLAG"] = get_variable ("F77_INTEGER8_FLAG", %OCTAVE_CONF_F77_INTEGER_8_FLAG%); vars["ALL_FFLAGS"] = vars["FFLAGS"] + ' ' + vars["F77_INTEGER8_FLAG"]; @@ -888,10 +883,6 @@ { ++i; - // FIXME: Remove LFLAGS checking in Octave 9 - if (argv[i] == "LFLAGS") - std::cerr << "mkoctfile: warning: LFLAGS is deprecated and will be removed in a future version of Octave, use LDFLAGS instead" << std::endl; - if (! var_to_print.empty ()) std::cerr << "mkoctfile: warning: only one '" << arg << "' option will be processed" << std::endl; @@ -1317,13 +1308,12 @@ octave_libs = "-L" + quote_path (vars["OCTLIBDIR"]) + ' ' + vars["OCTAVE_LIBS"]; - // FIXME: Remove LFLAGS in Octave 9 std::string cmd = (vars["CXXLD"] + ' ' + vars["CPPFLAGS"] + ' ' + vars["ALL_CXXFLAGS"] + ' ' + vars["RDYNAMIC_FLAG"] + ' ' + pass_on_options + ' ' + output_option + ' ' + objfiles + ' ' + libfiles + ' ' + ldflags + ' ' + vars["ALL_LDFLAGS"] + ' ' - + vars["LFLAGS"] + ' ' + octave_libs + ' ' + + octave_libs + ' ' + vars["OCTAVE_LINK_OPTS"] + ' ' + vars["OCTAVE_LINK_DEPS"]); int status = run_command (cmd, verbose, printonly); @@ -1348,12 +1338,11 @@ + ' ' + vars["OCTAVE_LIBS"]; #endif - // FIXME: Remove LFLAGS in Octave 9 std::string cmd = (vars["CXXLD"] + ' ' + vars["ALL_CXXFLAGS"] + ' ' + pass_on_options + " -o " + octfile + ' ' + objfiles + ' ' + libfiles + ' ' + ldflags + ' ' + vars["DL_LDFLAGS"] + ' ' - + vars["LDFLAGS"] + ' ' + vars["LFLAGS"] + ' ' + octave_libs + ' ' + + vars["LDFLAGS"] + ' ' + octave_libs + ' ' + vars["OCT_LINK_OPTS"] + ' ' + vars["OCT_LINK_DEPS"]); #if defined (OCTAVE_USE_WINDOWS_API) || defined(CROSS) diff -r c2a0e546aab1 -r 3b7852a822e8 test/io.tst --- a/test/io.tst Fri Dec 02 10:11:46 2022 -0500 +++ b/test/io.tst Fri Dec 02 10:12:40 2022 -0500 @@ -297,6 +297,118 @@ %!assert (sscanf ('0177 08', '%i'), [127; 0; 8]) %!assert (sscanf ('0177 08', '%d'), [177; 8]) +## Extensive testing of '%c' +%!test +%! [val, cnt, msg, pos] = sscanf ('abcde', '%c'); +%! assert (val, 'abcde'); +%! assert (cnt, 5); +%! assert (msg, ''); +%! assert (pos, 6); +%! [val, cnt, msg, pos] = sscanf ('abcde', '%10c'); +%! assert (val, 'abcde'); +%! assert (cnt, 1); +%! assert (msg, ''); +%! assert (pos, 6); +%! [val, cnt, msg, pos] = sscanf ('abcde', '%3c'); +%! assert (val, 'abcde'); +%! assert (cnt, 2); +%! assert (msg, ''); +%! assert (pos, 6); +%! [val, cnt, msg, pos] = sscanf ('abcde', '%3c', 1); +%! assert (val, 'abc'); +%! assert (cnt, 1); +%! assert (msg, ''); +%! assert (pos, 4); +%! [val, cnt, msg, pos] = sscanf ('abcde', '%c', 5); +%! assert (val, 'abcde'); +%! assert (cnt, 5); +%! assert (msg, ''); +%! assert (pos, 6); + +## Extensive testing of '%s' +%!test +%! [val, cnt, msg, pos] = sscanf ('abcde', '%s'); +%! assert (val, 'abcde'); +%! assert (cnt, 1); +%! assert (msg, ''); +%! assert (pos, 6); +%! [val, cnt, msg, pos] = sscanf ('abcde', '%10s'); +%! assert (val, 'abcde'); +%! assert (cnt, 1); +%! assert (msg, ''); +%! assert (pos, 6); +%! [val, cnt, msg, pos] = sscanf ('abcde', '%3s'); +%! assert (val, 'abcde'); +%! assert (cnt, 2); +%! assert (msg, ''); +%! assert (pos, 6); +%! [val, cnt, msg, pos] = sscanf ('abcde', '%3s', 1); +%! assert (val, 'abc'); +%! assert (cnt, 1); +%! assert (msg, ''); +%! assert (pos, 4); +%! [val, cnt, msg, pos] = sscanf ('abcde', '%1s', 5); +%! assert (val, 'abcde'); +%! assert (cnt, 5); +%! assert (msg, ''); +%! assert (pos, 6); + +## Extensive testing of '%[]' +%!test +%! [val, cnt, msg, pos] = sscanf ('abcde', '%[a-c]'); +%! assert (val, 'abc'); +%! assert (cnt, 1); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 4); +%! [val, cnt, msg, pos] = sscanf ('abcde', '%10[a-c]'); +%! assert (val, 'abc'); +%! assert (cnt, 1); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 4); +%! [val, cnt, msg, pos] = sscanf ('abcde', '%2[a-c]'); +%! assert (val, 'abc'); +%! assert (cnt, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 4); +%! [val, cnt, msg, pos] = sscanf ('abcde', '%2[a-c]', 1); +%! assert (val, 'ab'); +%! assert (cnt, 1); +%! assert (msg, ''); +%! assert (pos, 3); +%! [val, cnt, msg, pos] = sscanf ('abcde', '%[a-c]', 1); +%! assert (val, 'abc'); +%! assert (cnt, 1); +%! assert (msg, ''); +%! assert (pos, 4); + +## Extensive testing of '%[^]' +%!test +%! [val, cnt, msg, pos] = sscanf ('abcde', '%[^de]'); +%! assert (val, 'abc'); +%! assert (cnt, 1); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 4); +%! [val, cnt, msg, pos] = sscanf ('abcde', '%10[^de]'); +%! assert (val, 'abc'); +%! assert (cnt, 1); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 4); +%! [val, cnt, msg, pos] = sscanf ('abcde', '%2[^de]'); +%! assert (val, 'abc'); +%! assert (cnt, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 4); +%! [val, cnt, msg, pos] = sscanf ('abcde', '%2[^de]', 1); +%! assert (val, 'ab'); +%! assert (cnt, 1); +%! assert (msg, ''); +%! assert (pos, 3); +%! [val, cnt, msg, pos] = sscanf ('abcde', '%[^de]', 1); +%! assert (val, 'abc'); +%! assert (cnt, 1); +%! assert (msg, ''); +%! assert (pos, 4); + ## bug #47741 %!assert (sscanf ('2147483647', '%d'), 2147483647) %!assert (sscanf ('2147483647', '%i'), 2147483647) @@ -389,10 +501,169 @@ %!test <*62723> %! [val, count, msg, pos] = sscanf ("p", "%c"); -%! assert (val, "p"); +%! assert (val, 'p'); +%! assert (count, 1); +%! assert (msg, ''); +%! assert (pos, 2); + +%!test <*62723> +%! [val, count, msg, pos] = sscanf (' ,1 ', ' %s ', 1); +%! assert (val, ',1'); %! assert (count, 1); -%! assert (msg, ""); -%! assert (pos, 2); +%! assert (msg, ''); +%! assert (pos, 5); + +## Test NaN at EOF +%!test <*63383> +%! [val, count, msg, pos] = sscanf ('2 3 n', '%f'); +%! assert (val, [2; 3]); +%! assert (count, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 5); +%! [val, count, msg, pos] = sscanf ('2 3 na', '%f'); +%! assert (val, [2; 3; NA]); +%! assert (count, 3); +%! assert (msg, ''); +%! assert (pos, 7); +%! [val, count, msg, pos] = sscanf ('2 3 nan', '%f'); +%! assert (val, [2; 3; NaN]); +%! assert (count, 3); +%! assert (msg, ''); +%! assert (pos, 8); + +## Test NaN within string +%!test <*63383> +%! [val, count, msg, pos] = sscanf ('2 3 n 4', '%f'); +%! assert (val, [2; 3]); +%! assert (count, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 5); +%! [val, count, msg, pos] = sscanf ('2 3 na 4', '%f'); +%! assert (val, [2; 3; NA; 4]); +%! assert (count, 4); +%! assert (msg, ''); +%! assert (pos, 9); +%! [val, count, msg, pos] = sscanf ('2 3 nan 4', '%f'); +%! assert (val, [2; 3; NaN; 4]); +%! assert (count, 4); +%! assert (msg, ''); +%! assert (pos, 10); + +## Test Inf at EOF +%!test <*63383> +%! [val, count, msg, pos] = sscanf ('2 3 i', '%f'); +%! assert (val, [2; 3]); +%! assert (count, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 5); +%! [val, count, msg, pos] = sscanf ('2 3 in', '%f'); +%! assert (val, [2; 3]); +%! assert (count, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 5); +%! [val, count, msg, pos] = sscanf ('2 3 inf', '%f'); +%! assert (val, [2; 3; Inf]); +%! assert (count, 3); +%! assert (msg, ''); +%! assert (pos, 8); + +## Test Inf within string +%!test <*63383> +%! [val, count, msg, pos] = sscanf ('2 3 i 4', '%f'); +%! assert (val, [2; 3]); +%! assert (count, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 5); +%! [val, count, msg, pos] = sscanf ('2 3 in 4', '%f'); +%! assert (val, [2; 3]); +%! assert (count, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 5); +%! [val, count, msg, pos] = sscanf ('2 3 inf 4', '%f'); +%! assert (val, [2; 3; Inf; 4]); +%! assert (count, 4); +%! assert (msg, ''); +%! assert (pos, 10); + +## Test '-' at EOF +%!test <*63383> +%! [val, count, msg, pos] = sscanf ('2 3 -', '%d'); +%! assert (val, [2; 3]); +%! assert (count, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 5); +%! [val, count, msg, pos] = sscanf ('2 3 -', '%f'); +%! assert (val, [2; 3]); +%! assert (count, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 5); + +## Test '-' within string +%!test <63383> +%! [val, count, msg, pos] = sscanf ('1 2 - 3', '%d'); +%! assert (val, [1; 2]); +%! assert (count, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 5); +%! [val, count, msg, pos] = sscanf ('1 2 - 3', '%f'); +%! assert (val, [1; 2]); +%! assert (count, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 5); + +## Test '+' at EOF +%!test <*63383> +%! [val, count, msg, pos] = sscanf ('2 3 +', '%d'); +%! assert (val, [2; 3]); +%! assert (count, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 5); +%! [val, count, msg, pos] = sscanf ('2 3 +', '%f'); +%! assert (val, [2; 3]); +%! assert (count, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 5); + +## Test '+' within string +%!test <63383> +%! [val, count, msg, pos] = sscanf ('1 2 + 3', '%d'); +%! assert (val, [1; 2]); +%! assert (count, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 5); +%! [val, count, msg, pos] = sscanf ('1 2 + 3', '%f'); +%! assert (val, [1; 2]); +%! assert (count, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 5); + +%## Test +NA, -NA, +NAN, -NAN +%!test <*63383> +%! [val, count, msg, pos] = sscanf ('+NA -NA 1 +NAN -NAN', '%f'); +%! assert (val, [NA; NA; 1; NaN; NaN]); +%! assert (count, 5); +%! assert (msg, ''); +%! assert (pos, 20); +%! [val, count, msg, pos] = sscanf ('-NA', '%f'); +%! assert (val, NA); +%! assert (count, 1); +%! assert (msg, ''); +%! assert (pos, 4); +%! [val, count, msg, pos] = sscanf ('+NA', '%f'); +%! assert (val, NA); +%! assert (count, 1); +%! assert (msg, ''); +%! assert (pos, 4); +%! [val, count, msg, pos] = sscanf ('-NaN', '%f'); +%! assert (val, NaN); +%! assert (count, 1); +%! assert (msg, ''); +%! assert (pos, 5); +%! [val, count, msg, pos] = sscanf ('+NaN', '%f'); +%! assert (val, NaN); +%! assert (count, 1); +%! assert (msg, ''); +%! assert (pos, 5); %!test %! [a, b, c] = sscanf ("1.2 3 foo", "%f%d%s", "C"); @@ -403,14 +674,16 @@ %! && v1 == [1; 2; 3; 4; 5; 6] && c1 == 6 && ischar (m1) %! && v2 == [1; 2] && c2 == 2 && ischar (m2))); -%!error sscanf () -%!error sscanf (1, 2) -%!error sscanf ("foo", "bar", "C", 1) - %!test %! [x, n] = sscanf (" 0.024000 0.200 0.200 2.000 1987 5 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 2 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 4 5 1 2 2 5 5 8 2 8 12 6 15 18 28 26 47 88 118 162 192 130 88 56 27 23 14 9 6 3 4 1 0 2 3 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0.026000 0.250 0.250 2.100 3115 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 2 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 1 1 0 1 1 1 0 1 0 1 3 2 0 5 15 25 44 66 145 179 193 172 104 57 17 11 12 2 1 0 1 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.028000 0.300 0.300 2.200 4929 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1 2 2 3 2 3 14 21 49 80 148 184 218 159 124 63 37 13 12 3 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.030000 0.350 0.350 2.300 7051 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 0 2 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 0 0 2 0 0 0 1 5 6 14 28 51 88 154 177 208 169 124 65 39 15 5 3 3 2 1 0 1 0 1 0 0 0 0 1 1 1 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.032000 0.400 0.400 2.400 9113 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 2 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 2 0 1 0 0 1 1 0 2 3 5 3 17 30 60 117 156 189 209 129 102 64 56 16 11 4 2 2 0 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0.034000 0.450 0.450 2.500 11811 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 2 1 0 0 1 0 5 5 15 21 57 99 149 190 195 159 130 69 41 16 10 2 5 3 0 1 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.036000 0.500 0.500 2.600 14985 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 0 0 2 2 6 10 34 60 95 126 177 194 155 99 71 44 17 6 7 2 0 0 0 3 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.038000 0.550 0.550 2.700 18391 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 2 0 0 1 1 0 1 2 1 0 0 0 1 0 1 3 6 19 27 52 95 161 154 169 134 94 64 37 19 9 6 0 2 1 0 0 0 0 1 2 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 2 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.040000 0.600 0.600 2.800 22933 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 2 0 3 4 7 18 27 47 82 134 163 133 138 101 58 34 26 10 5 2 1 2 1 1 0 2 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0.042000 0.650 0.650 2.900 27719 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 1 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 2 8 16 37 51 87 128 153 146 123 105 62 35 24 8 3 5 0 1 2 1 0 0 0 1 1 1 0 0 0 1 0 1 0 0 2 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.044000 0.700 0.700 3.000 32922 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 0 2 0 0 0 0 0 0 0 0 2 1 0 0 0 0 1 1 1 1 0 0 1 0 0 0 1 0 0 0 0 0 0 1 1 0 0 0 1 0 1 1 1 1 0 0 0 1 4 3 5 5 15 35 54 88 132 168 149 105 92 62 30 16 17 4 5 1 0 0 1 0 1 1 0 1 1 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.046000 0.750 0.750 3.100 38973 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 1 0 0 0 4 3 5 20 37 56 94 110 135 149 124 84 58 36 17 14 7 1 0 2 0 1 0 0 1 1 0 0 0 0 0 1 1 0 0 0 1 0 1 1 0 0 1 1 1 0 0 0 0 1 1 0 0 1 0 0 0 0 1 0 0 0 1 1 0 1 0 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.048000 0.800 0.800 3.200 45376 5 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 1 1 0 0 2 1 1 2 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 3 18 34 55 82 104 135 116 99 79 60 51 29 10 4 3 1 1 1 0 0 1 0 0 0 1 0 0 3 1 2 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.050000 0.850 0.850 3.300 52060 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 1 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 2 2 1 3 12 24 40 39 107 121 127 138 100 86 68 44 23 15 7 3 1 1 0 1 1 0 0 2 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 1 1 0 1 0 0 0 2 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.052000 0.900 0.900 3.400 59454 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 1 0 0 0 1 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 2 0 0 0 0 0 0 1 0 0 0 0 1 0 1 0 1 0 0 2 0 2 1 0 0 0 1 0 0 1 0 0 0 0 0 3 3 6 21 32 68 90 132 111 122 107 73 57 47 24 11 7 4 2 2 1 0 0 0 0 0 0 0 0 1 0 0 1 0 0 2 0 1 1 0 0 1 0 0 0 0 0 3 0 1 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0.054000 0.950 0.950 3.500 67013 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 1 0 0 0 0 1 0 0 1 1 0 0 0 1 0 1 0 1 2 4 3 7 9 28 31 71 94 115 96 108 78 82 60 38 17 12 11 4 3 1 1 0 2 1 0 0 0 2 1 3 0 0 0 0 3 0 0 1 0 0 0 0 0 0 0 2 0 0 0 1 0 2 0 1 0 2 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0.056000 1.000 1.000 3.600 75475 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1 3 0 0 1 1 2 0 1 4 0 1 8 6 7 17 41 56 71 109 113 84 103 72 54 35 22 6 9 1 7 5 4 0 0 1 0 0 0 0 0 0 1 0 0 2 1 0 0 0 0 2 0 0 1 0 0 1 0 0 0 0 0 0 1 0 2 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 3 0 0 0 1 0 0 0 0 0 0 1 1 0 0 2 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0.058000 1.050 1.050 3.700 83558 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 1 2 0 0 2 0 0 1 0 3 2 3 6 15 27 41 77 73 94 94 92 76 61 56 42 23 13 11 6 2 1 2 0 1 2 0 0 1 0 1 0 0 1 0 0 1 1 1 0 0 0 1 0 0 0 1 0 0 0 0 1 1 0 0 0 0 2 0 0 0 0 0 1 2 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0.060000 1.100 1.100 3.800 93087 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 1 2 2 0 0 0 1 0 1 1 0 0 0 1 1 0 4 0 0 1 2 0 3 1 3 5 13 33 31 65 75 77 96 97 80 59 45 36 32 18 2 5 0 1 0 0 1 0 0 3 0 0 0 0 1 0 0 0 0 0 1 0 0 1 2 0 0 0 0 1 0 0 0 0 1 0 1 1 1 0 0 2 0 0 2 0 1 0 0 0 0 0 0 0 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.062000 1.150 1.150 3.900 102829 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 0 0 1 0 1 0 0 0 0 0 1 1 1 0 1 0 1 1 0 1 1 0 2 0 2 1 2 0 0 2 4 3 5 11 9 23 43 53 68 65 87 83 77 59 49 34 18 15 9 4 2 3 2 0 0 0 4 0 1 1 0 0 2 0 0 1 0 0 0 0 1 1 1 0 1 0 0 0 0 2 0 0 0 0 1 0 0 1 1 1 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0.064000 1.200 1.200 4.000 113442 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 1 1 1 0 1 1 1 1 1 0 0 0 1 2 0 0 0 2 0 4 5 11 13 29 39 61 68 61 75 76 74 73 44 37 29 19 6 3 3 2 0 1 2 1 0 0 0 0 1 1 1 0 1 1 0 0 0 1 0 1 1 0 1 2 0 2 1 1 1 0 0 0 0 1 0 0 1 1 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0 2 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0.066000 1.250 1.250 4.100 126668 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 1 0 0 0 1 1 2 3 0 2 1 2 0 1 0 3 0 0 0 1 0 1 1 3 0 0 1 3 0 2 4 3 12 12 30 48 56 66 77 78 71 82 52 31 32 19 20 16 8 2 1 3 0 0 2 1 0 1 0 1 0 0 0 1 3 1 0 1 0 1 1 1 0 0 0 0 0 2 0 2 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 2 0 3 1 0 0 1 0 0 0 0 0 0 1 0 1 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.068000 1.300 1.300 4.200 138042 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 2 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 2 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 3 0 0 1 0 0 1 2 0 0 0 3 0 1 0 0 3 0 1 0 1 1 3 1 4 7 11 14 27 36 44 68 72 70 71 45 44 46 29 13 16 11 5 2 0 3 0 0 0 0 1 1 2 0 0 1 1 2 1 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1 2 0 0 1 1 0 1 1 1 0 0 1 0 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.070000 1.350 1.350 4.300 152335 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 2 0 0 0 1 0 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 2 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 2 0 0 0 0 1 1 1 0 1 1 0 1 1 1 1 0 2 0 0 0 0 0 2 0 1 7 14 19 34 35 54 72 68 72 68 58 48 36 37 27 25 17 1 4 1 0 0 0 1 2 2 0 0 1 1 1 2 1 0 3 1 0 1 0 2 1 0 0 0 1 1 1 2 0 0 0 0 1 1 0 1 1 0 2 1 1 1 1 0 0 0 1 1 0 0 2 0 0 1 0 0 0 1 1 0 2 1 1 0 0 0 0 2 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 2 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0.072000 1.400 1.400 4.400 166280 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 1 0 1 1 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 2 0 0 0 0 0 0 0 1 0 1 0 1 1 1 0 0 1 0 1 0 0 3 4 2 2 0 0 0 0 0 1 1 3 1 0 3 2 2 1 2 2 0 2 2 1 8 14 26 24 29 47 47 68 65 63 55 42 41 26 29 17 8 4 4 1 0 1 2 0 0 0 1 1 2 0 1 2 1 0 0 1 1 1 0 0 1 0 0 0 1 0 0 1 2 1 2 1 0 0 0 0 0 1 1 2 0 2 2 0 0 0 0 1 1 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0.074000 1.450 1.450 4.500 179484 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 1 0 1 0 0 1 0 1 2 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 1 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 1 1 0 1 1 1 2 0 0 1 1 2 1 0 1 1 2 2 0 1 5 6 10 20 43 50 57 62 53 62 66 45 42 33 27 26 23 14 3 0 2 0 1 0 0 1 1 0 0 2 1 1 0 0 3 0 1 1 1 0 1 1 0 1 0 1 2 1 0 0 1 2 0 2 0 0 0 0 1 1 3 1 0 0 2 1 1 1 0 0 0 0 0 0 1 2 0 1 0 0 0 0 0 1 1 0 2 0 0 0 0 0 1 0 2 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0.076000 1.500 1.500 4.600 197657 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 2 0 0 0 1 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 2 0 0 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 2 0 0 0 2 1 1 0 1 1 0 1 1 3 2 1 1 2 1 0 1 0 0 0 0 0 1 1 1 0 5 3 7 12 24 38 32 41 48 54 66 71 49 46 31 38 25 15 8 6 6 5 0 1 3 0 1 1 1 1 1 0 1 2 0 1 0 0 0 1 0 2 1 2 0 0 0 0 1 3 1 0 0 0 0 1 1 0 1 0 1 1 1 1 1 0 4 1 1 1 0 3 0 0 0 2 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0.078000 1.550 1.550 4.700 212054 3 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 1 0 0 0 0 0 1 0 1 1 0 0 1 0 0 1 0 0 0 0 0 0 0 1 1 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 2 0 0 0 1 0 0 1 0 1 1 0 1 3 1 0 0 1 2 0 0 0 1 0 0 0 0 0 2 1 2 1 1 1 0 0 1 5 1 1 2 3 5 7 9 11 22 31 37 48 50 52 54 57 37 38 38 33 24 11 19 11 3 1 2 0 3 3 2 1 0 1 3 0 1 1 1 1 1 2 0 0 0 1 1 2 0 1 1 3 0 1 1 0 0 1 0 2 0 1 0 0 1 3 0 2 0 1 0 1 2 0 1 1 1 1 1 0 3 0 1 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 0 0 0.080000 1.600 1.600 4.800 231971 3 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 2 0 0 0 1 1 1 0 1 0 0 0 0 1 0 1 1 0 0 0 0 2 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 2 1 0 1 1 1 0 1 0 0 1 0 1 3 0 0 0 1 0 0 0 1 1 1 0 0 4 1 1 0 2 0 1 1 1 2 0 0 0 1 0 1 2 1 2 3 2 0 1 0 4 3 1 1 1 1 3 1 0 0 0 2 1 0 2 7 17 13 29 47 58 59 52 38 51 51 38 34 35 21 14 13 4 1 0 1 1 1 0 2 2 4 1 0 1 1 4 0 0 0 2 0 2 2 2 0 0 1 3 2 1 1 2 2 2 2 1 0 3 0 2 1 2 1 2 2 0 0 1 1 0 2 0 2 2 0 1 0 2 2 3 1 2 3 1 1 0 1 0 2 0 1 2 1 2 0 2 1 0 0 3 0 0 1 1 1 1 0 0 1 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0.082000 1.650 1.650 4.900 252503 3 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 2 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 2 0 0 1 0 1 2 2 2 1 0 2 0 1 0 1 1 2 2 0 3 0 0 4 1 0 0 3 0 0 1 2 0 1 1 1 3 0 1 0 2 9 11 25 27 34 53 41 49 43 47 36 31 38 22 30 22 18 9 5 9 2 2 1 2 2 3 1 4 1 1 0 0 1 2 0 2 1 0 0 1 3 2 2 1 0 0 0 1 2 1 0 0 0 2 1 1 0 2 0 0 1 0 0 2 1 3 1 1 1 0 2 1 1 0 2 1 0 1 3 0 0 0 0 2 0 0 1 0 0 0 0 0 1 2 1 1 1 0 2 1 0 0 0 2 0 1 0 0 0 0 1 0 0 0 0 1 0 0 2 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0.084000 1.700 1.700 5.000 267889 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 0 3 0 1 1 1 0 1 2 1 0 2 0 2 4 0 1 0 0 0 1 1 0 1 3 2 0 2 0 4 0 0 2 0 1 4 2 4 3 3 6 10 14 28 37 54 36 40 52 40 50 46 40 32 26 29 12 18 5 2 0 2 4 1 2 1 0 2 1 2 2 1 0 1 0 2 1 2 4 1 1 5 1 0 2 0 1 2 3 2 2 1 2 1 0 2 1 2 1 1 4 1 2 1 4 0 2 2 0 0 3 1 0 2 0 0 1 1 1 0 0 2 1 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0.086000 1.750 1.750 5.100 290294 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 2 0 0 0 1 0 0 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 3 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 2 1 0 1 0 1 0 0 2 2 0 1 2 2 0 2 0 2 0 1 0 0 1 1 1 3 1 1 1 1 3 4 1 1 2 2 2 1 0 3 0 0 0 2 4 5 6 16 18 20 31 40 54 55 46 41 52 35 27 21 28 27 20 15 8 6 7 1 0 0 3 0 0 2 2 0 3 1 3 1 1 2 0 0 1 2 1 3 2 0 1 2 1 3 1 1 1 1 1 2 0 2 1 0 1 1 1 3 1 1 2 0 1 0 1 0 2 1 1 0 0 1 2 0 3 1 1 0 0 0 1 3 1 1 1 0 0 1 2 1 0 0 1 1 1 0 0 1 0 0 0 0 0 0 2 0 1 0 0 0 2 1 0 2 0 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0.088000 1.800 1.800 5.200 312476 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 1 0 1 0 1 1 0 0 0 0 0 0 2 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 2 0 0 0 1 0 1 0 0 0 0 0 0 2 1 0 0 1 0 0 1 1 1 1 4 2 0 1 0 0 3 0 0 0 0 0 1 1 4 0 0 0 0 1 1 2 1 0 3 0 0 2 2 4 0 3 1 6 9 10 13 21 24 32 43 33 41 43 49 50 32 26 31 27 12 16 17 3 3 3 5 0 3 0 2 1 3 3 2 1 2 3 1 2 1 1 1 2 0 1 1 0 2 0 3 0 0 2 0 0 0 0 1 0 1 1 3 3 0 1 1 1 1 1 1 2 2 2 0 3 1 0 2 2 2 0 0 0 0 3 1 2 5 1 1 2 0 0 3 3 0 2 2 0 0 0 0 1 2 0 0 1 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0.090000 1.850 1.850 5.300 337348 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 2 0 1 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 2 0 1 1 0 0 0 1 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 2 0 0 0 1 3 2 0 0 2 2 3 3 2 2 2 0 0 1 1 3 1 3 0 0 0 0 0 0 1 2 1 2 1 2 2 2 0 1 1 0 4 2 2 7 6 15 22 21 39 37 50 31 51 30 33 34 34 26 21 14 13 10 9 4 3 3 4 2 2 0 1 2 3 3 0 1 3 2 5 3 2 2 4 0 2 3 0 4 2 1 2 2 2 4 2 1 3 1 3 2 1 3 1 2 4 1 1 1 1 2 4 1 3 3 3 1 0 4 1 0 1 1 1 1 2 3 0 3 0 0 4 1 1 1 0 2 2 2 1 2 2 0 1 1 0 0 0 2 0 1 0 1 0 0 1 0 0 0 1 3 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 0 0.092000 1.900 1.900 5.400 357303 3 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 0 1 1 0 1 0 0 1 0 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 3 1 0 1 0 0 0 0 1 0 0 1 0 0 1 1 2 2 0 0 2 2 1 1 1 1 1 1 0 1 0 0 1 1 1 3 1 1 1 1 1 0 1 4 0 1 1 1 3 0 1 1 2 2 2 0 2 3 2 2 2 2 1 2 1 3 8 22 14 32 36 46 39 42 39 29 36 38 26 24 26 18 16 19 10 9 3 6 5 0 3 2 1 1 1 2 0 2 1 1 0 1 1 3 1 0 2 4 2 2 1 4 1 2 2 1 1 0 1 2 0 2 2 2 4 2 1 1 0 2 1 3 1 2 3 4 2 3 2 3 0 1 2 1 0 0 0 4 1 1 1 2 1 3 1 0 5 1 0 0 0 0 0 0 1 0 2 0 1 2 1 0 1 0 0 0 0 0 1 1 0 1 0 1 4 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0.094000 1.950 1.950 5.500 383138 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 1 1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 2 1 0 1 1 1 0 0 0 0 0 0 1 1 0 1 0 0 1 1 0 1 0 0 0 0 0 0 0 2 1 1 1 1 2 1 0 2 0 1 0 3 2 1 3 0 1 3 1 1 0 5 0 1 0 1 2 0 0 1 1 2 0 0 6 1 0 3 2 2 3 4 5 0 4 2 1 5 4 11 15 22 27 28 57 38 38 40 38 39 38 27 26 30 18 14 10 10 4 4 4 3 3 2 2 2 2 1 1 1 1 2 2 3 4 1 2 3 1 2 1 2 2 2 1 3 2 1 5 0 1 1 1 3 2 2 2 1 3 1 1 0 3 2 2 0 0 2 2 2 0 0 0 2 0 1 3 1 2 3 2 1 1 0 1 1 1 0 3 2 2 1 0 0 1 3 1 1 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 3 1 0 0 0 0 1 0 1 1 0 0 0 1 0 0 0 0 0 0.096000 2.000 2.000 5.600 409868 3 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0 1 0 1 0 1 0 2 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 2 0 1 0 0 2 0 2 0 0 0 0 1 0 0 2 1 2 2 2 1 2 1 1 1 1 1 2 0 0 1 1 0 1 0 2 1 2 0 2 0 3 1 2 1 3 1 5 0 2 2 1 2 4 1 2 0 3 1 4 7 5 9 13 22 19 31 27 28 41 34 39 37 22 23 21 22 17 23 15 8 9 3 8 0 3 1 2 2 2 3 1 0 4 2 4 2 2 2 2 4 2 1 1 0 2 0 3 0 3 2 2 1 2 2 1 4 1 2 2 1 1 5 2 1 2 1 2 2 1 0 2 4 3 2 1 2 2 3 2 3 1 2 1 1 1 1 2 1 1 2 2 1 2 3 2 1 1 0 2 2 4 0 1 1 1 1 1 0 0 1 1 3 0 0 0 0 0 1 0 0 2 0 1 2 0 1 1 1 0 1 0 1 0 0 0.098000 2.050 2.050 5.700 439102 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 1 1 0 0 1 0 1 0 1 0 0 0 0 1 1 0 1 0 0 1 1 0 0 1 1 0 0 1 1 0 1 0 0 0 0 0 0 0 1 2 0 0 1 1 1 1 2 0 1 1 0 0 0 0 1 1 1 0 4 0 0 0 2 1 1 0 3 4 0 1 2 2 1 0 3 0 3 2 0 0 2 0 1 0 0 1 0 1 3 1 3 5 0 2 2 3 5 2 2 2 0 3 2 3 6 5 16 21 19 23 28 29 35 42 42 44 39 33 23 30 18 25 24 15 13 5 4 2 2 0 3 3 0 0 1 3 0 1 1 3 2 4 3 4 2 1 1 1 3 1 0 0 2 2 4 2 2 1 4 2 4 2 2 2 1 2 2 1 2 0 4 2 2 3 1 2 1 1 2 2 1 2 4 2 1 4 1 2 2 2 2 0 2 0 3 0 1 0 2 1 0 4 2 1 3 2 1 0 2 1 1 1 1 0 1 1 2 1 1 1 2 0 1 0 2 1 1 0 0 1 0 0 1 0 0 0 0 0 0 0.100000 2.100 2.100 5.800 467340 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 1 0 0 1 2 0 0 0 0 0 1 0 2 0 0 2 0 0 1 1 0 0 0 1 0 0 1 1 0 0 0 0 1 1 0 0 1 0 0 1 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 1 2 0 2 2 4 1 0 1 1 2 3 4 1 4 1 5 1 2 1 0 2 2 2 1 5 4 1 5 4 0 1 2 4 2 2 0 2 1 2 5 4 1 1 1 2 5 7 9 16 23 31 15 22 36 36 44 42 29 31 28 28 18 35 12 10 13 8 4 3 2 2 5 1 2 3 3 1 3 3 5 2 0 3 4 1 2 2 3 0 0 5 2 3 6 2 1 2 5 3 4 3 1 1 1 1 2 2 4 0 2 3 1 2 1 2 4 5 4 3 5 2 1 2 0 5 0 2 2 4 1 0 4 1 0 2 1 2 0 0 1 3 2 4 3 0 2 3 3 3 4 2 2 0 0 0 0 1 1 0 3 2 0 1 2 0 4 2 1 1 1 2 0 0 0 0 0 0 0 0 0 0 0.102000 2.150 2.150 5.900 497495 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 0 2 1 0 0 0 0 1 0 1 0 0 0 0 1 2 0 0 0 0 0 2 0 0 1 0 1 0 0 0 0 1 1 0 0 0 1 1 1 1 2 0 0 1 0 0 0 1 0 2 2 1 0 0 0 2 0 2 1 1 1 6 3 2 0 3 2 2 2 1 1 3 4 1 0 1 2 4 2 3 3 1 1 1 1 3 3 1 4 1 3 4 3 2 3 1 2 2 5 11 11 14 26 27 28 28 28 36 39 42 29 33 24 20 29 18 13 17 13 6 10 4 3 3 6 1 0 1 0 2 1 3 2 3 1 2 3 1 2 1 2 0 2 2 3 1 3 1 1 2 4 4 1 4 3 2 2 3 5 5 3 0 2 5 3 5 1 4 1 1 3 4 2 2 2 2 1 3 0 1 1 2 2 4 2 1 3 2 0 1 2 1 0 2 3 1 2 0 0 0 2 0 0 1 3 0 0 1 2 0 3 1 0 3 1 2 2 1 1 2 0 0 0 0 2 0 0 1 0 0 0 0 0 0.104000 2.200 2.200 6.000 529288 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 2 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 1 3 0 2 0 2 0 0 3 2 2 0 4 0 3 2 2 1 3 1 7 3 1 1 0 4 3 2 1 0 0 3 2 3 5 2 1 4 1 5 1 0 3 2 3 0 1 2 4 7 3 7 8 12 15 20 24 34 39 34 35 27 36 34 23 22 26 15 24 12 12 14 5 3 0 7 1 1 3 5 1 2 2 2 4 3 1 2 5 2 2 3 1 1 4 2 1 3 0 4 5 4 6 4 5 3 3 3 3 1 1 5 0 6 1 2 4 2 3 2 1 3 2 0 0 0 1 3 3 0 1 4 0 3 2 3 0 3 3 0 2 3 4 3 1 1 1 2 5 3 1 2 1 1 2 4 1 0 2 4 1 3 0 0 3 0 1 3 0 1 0 0 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0.106000 2.250 2.250 6.100 560628 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 2 0 1 0 1 0 1 0 1 0 0 1 0 0 0 0 0 0 1 1 0 1 1 0 0 1 1 1 0 1 1 0 0 0 1 1 1 1 0 0 1 1 2 0 0 0 0 2 0 3 1 1 0 0 2 2 2 0 5 2 1 1 1 1 3 1 2 3 0 1 0 0 0 0 1 0 2 2 1 2 1 0 4 3 2 1 2 1 0 4 2 2 0 2 1 1 2 3 1 2 1 2 4 4 11 12 17 19 19 29 30 24 30 35 51 32 36 34 31 19 22 17 11 19 11 7 6 6 3 4 0 3 3 2 0 2 2 2 3 1 5 3 2 3 5 1 0 2 2 5 4 2 3 2 0 1 6 1 2 2 2 2 1 1 2 2 1 4 3 2 2 1 2 5 2 0 2 0 2 5 4 5 2 1 3 6 1 3 4 4 0 0 6 0 2 6 1 2 2 2 0 1 3 1 3 4 2 1 4 2 1 2 3 3 0 3 1 0 2 0 2 1 0 2 1 2 0 0 1 1 0 2 0 0 0 0 0 0 0 0.108000 2.300 2.300 6.200 593293 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 2 0 2 2 1 0 0 2 0 1 0 1 0 0 1 2 2 1 0 0 1 0 2 0 0 0 0 0 1 1 1 1 1 0 0 1 1 0 0 1 1 1 2 2 1 0 1 1 0 1 5 0 2 4 1 0 1 4 2 1 3 2 2 3 2 3 2 0 0 3 4 3 1 3 2 2 0 3 0 2 4 0 3 2 5 1 2 1 4 6 1 2 4 0 3 6 1 7 6 4 5 4 10 16 24 22 20 40 37 44 34 29 21 28 36 36 27 23 24 14 10 4 5 2 5 3 6 2 3 3 1 4 2 1 5 1 3 5 3 2 1 2 2 6 2 3 1 1 0 5 3 3 3 4 5 2 2 3 3 5 5 1 6 2 3 2 6 0 5 2 4 3 5 1 2 2 5 1 2 3 1 2 2 2 4 2 5 5 2 2 2 5 0 1 2 5 2 3 2 3 1 1 2 4 0 2 1 4 2 1 1 1 0 1 2 0 0 1 3 1 0 2 1 1 3 3 2 0 0 0 1 2 0 0 0 0 0.110000 2.350 2.350 6.300 636559 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 1 0 0 0 1 1 2 0 0 1 0 0 0 0 0 0 0 1 2 0 0 1 1 1 0 0 0 0 1 0 1 1 0 0 1 0 0 2 0 1 0 1 0 1 0 0 1 1 3 0 1 2 2 0 2 1 1 1 1 0 1 0 1 3 0 3 2 3 4 3 3 4 3 3 2 6 3 1 1 1 2 4 2 3 1 5 1 3 1 4 5 3 3 2 1 3 7 4 3 10 19 17 19 23 27 28 33 39 36 23 23 32 32 16 19 35 23 12 11 12 8 4 5 7 1 2 2 1 2 3 5 4 2 3 2 6 4 4 2 4 1 2 2 1 2 3 0 4 2 1 2 6 2 2 1 3 3 1 6 4 8 5 2 3 5 2 3 0 3 2 3 1 2 2 3 4 3 8 6 2 1 4 6 3 1 2 0 2 0 2 5 0 3 3 3 3 1 3 3 2 5 4 2 1 4 2 2 4 4 1 3 2 5 2 3 1 2 0 4 0 1 0 6 3 1 2 0 2 0 1 0 0 0 0 0.112000 2.400 2.400 6.400 670484 3 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 1 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 2 0 1 1 1 3 0 0 0 2 1 3 0 1 1 1 0 1 1 1 0 0 1 2 0 1 3 1 5 2 3 0 4 0 2 0 0 1 2 1 0 1 0 0 1 0 2 2 3 2 3 2 2 2 3 4 4 2 3 5 3 3 2 3 3 4 2 4 0 3 2 4 4 1 3 1 3 4 2 2 5 2 8 6 12 17 14 22 27 26 29 39 30 24 36 22 22 20 9 19 15 5 12 16 4 7 5 7 5 5 1 4 5 5 4 4 1 4 4 3 3 3 4 2 2 4 2 4 4 4 4 0 2 3 2 1 4 3 6 1 3 3 3 4 5 4 2 2 2 5 3 0 2 5 4 2 5 3 5 1 1 3 1 1 3 6 6 2 3 2 0 3 2 4 3 4 1 2 2 6 2 0 3 2 2 5 3 3 5 2 1 0 3 1 1 2 2 0 1 1 3 2 3 2 1 1 1 1 3 2 1 0 0 0 0 0 0 0 0.114000 2.450 2.450 6.500 711783 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 0 1 0 2 1 2 0 1 0 0 1 0 0 1 1 1 1 0 0 0 1 1 2 0 1 1 0 0 0 2 1 1 1 1 1 2 1 2 3 3 1 1 1 2 3 1 3 2 2 1 0 1 1 4 4 4 1 0 4 0 0 1 1 2 1 3 2 0 3 4 1 1 1 1 3 2 0 1 3 2 1 2 1 0 3 3 2 5 4 2 5 3 4 2 2 5 3 3 3 3 5 5 8 7 14 12 28 22 24 23 36 33 26 32 27 26 18 30 24 15 13 19 15 17 6 5 7 5 4 3 5 3 1 4 4 9 5 3 1 4 0 0 6 2 5 3 3 3 1 2 3 2 4 1 5 5 3 8 2 1 1 4 1 7 5 6 6 4 4 3 2 6 3 3 3 3 1 3 4 5 4 3 4 3 1 2 3 1 2 1 2 2 6 5 2 2 2 4 2 2 0 2 3 3 2 7 4 4 1 4 2 0 3 1 1 2 1 2 3 1 3 2 2 4 3 1 4 0 0 4 2 2 2 1 0 0 0 0 0.116000 2.500 2.500 6.600 745364 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 1 2 1 1 2 1 1 1 0 1 0 2 0 1 1 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 1 1 2 3 0 1 4 4 0 4 0 1 0 1 3 3 0 2 1 2 3 2 1 1 1 2 0 4 0 0 4 5 2 5 4 1 3 5 5 4 0 4 4 2 3 2 3 5 2 2 4 2 3 4 2 3 3 3 3 3 2 4 12 10 13 14 19 22 23 24 36 19 32 25 25 36 24 18 20 21 14 18 13 8 6 9 2 9 5 2 5 3 4 4 3 3 0 4 3 2 5 3 4 2 2 6 3 4 0 2 4 1 3 4 7 4 5 3 2 4 5 5 3 4 4 4 2 3 2 4 4 2 1 5 7 1 5 2 4 1 5 5 3 4 4 3 2 4 2 4 0 6 2 3 4 1 2 2 2 4 1 4 2 2 2 5 6 5 1 4 4 2 3 3 3 1 4 3 4 2 6 2 5 3 2 2 1 3 2 2 5 1 1 0 0 1 0 0 0 0.118000 2.550 2.550 6.700 791846 4 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 2 1 1 0 0 0 0 0 1 0 0 0 1 1 0 1 0 1 0 1 1 0 1 0 1 4 1 2 3 0 3 1 0 1 1 1 0 3 1 2 1 1 1 0 0 1 1 1 3 1 3 2 3 1 2 2 1 3 2 4 1 4 0 2 4 1 4 3 2 1 1 2 1 3 2 3 3 2 1 1 5 3 3 3 3 2 3 4 3 5 3 1 1 2 2 3 5 1 2 1 1 4 4 6 9 6 6 13 17 21 20 24 22 25 20 29 23 28 30 26 27 18 20 17 16 17 12 10 8 5 6 6 6 4 3 1 2 4 6 9 2 2 3 5 7 6 2 3 8 5 4 5 6 4 6 5 3 5 3 2 5 3 2 8 3 5 4 5 3 5 4 3 4 8 4 3 8 3 3 3 1 1 2 2 5 4 7 3 2 3 3 2 2 3 6 3 2 2 1 1 5 2 5 6 3 5 3 4 1 3 1 2 1 0 4 1 4 2 2 2 3 1 1 1 1 3 2 0 1 6 1 1 0 2 1 0 1 0 0 0 0 0.120000 2.600 2.600 6.800 833394 3 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 2 2 1 1 1 2 1 0 0 0 1 0 1 0 0 0 1 0 0 1 1 2 1 0 0 0 0 0 2 2 0 3 1 0 0 2 1 1 1 1 0 1 2 1 5 0 1 0 2 2 1 2 0 4 2 1 4 3 4 2 2 1 2 1 5 2 3 1 3 0 2 2 2 2 3 4 0 4 2 3 3 4 5 2 2 6 3 4 5 5 5 3 4 6 5 1 3 0 5 4 5 1 3 2 2 6 18 13 17 27 27 21 28 28 24 26 27 29 23 21 16 17 19 22 14 11 9 5 14 7 7 6 4 4 12 3 6 4 5 4 6 4 2 0 1 8 1 6 8 5 2 3 4 5 6 4 2 5 8 3 1 1 6 3 7 8 4 1 6 5 2 8 11 5 6 5 6 2 4 5 1 2 7 2 2 5 5 6 3 3 2 3 8 5 1 9 3 3 2 3 6 3 5 3 2 4 6 3 1 3 5 4 4 4 6 3 3 5 0 2 2 5 1 3 2 2 1 4 2 0 2 2 2 2 4 1 2 1 2 1 1 0 0.122000 2.650 2.650 6.900 876007 3 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 2 1 1 1 1 2 2 1 0 0 1 0 0 0 1 1 0 0 0 2 0 0 4 1 0 2 1 2 0 1 2 0 1 3 2 1 0 1 1 0 1 2 1 0 2 3 3 5 3 3 3 0 1 4 0 1 5 3 4 3 1 2 2 2 4 1 3 3 3 2 3 2 3 2 1 4 4 2 2 5 5 3 4 1 2 1 2 4 2 4 7 2 4 4 2 7 3 5 7 5 3 6 8 10 10 18 21 22 24 14 25 27 29 31 22 25 24 21 27 20 19 22 19 14 13 14 10 5 7 3 4 5 5 3 1 4 3 8 4 5 4 0 3 4 3 4 1 7 6 1 1 3 4 4 3 4 3 6 4 3 4 2 4 4 3 5 6 5 1 1 6 2 6 6 3 5 5 3 2 6 5 4 3 4 6 4 3 5 5 6 5 6 2 4 2 1 2 2 4 2 7 6 2 1 3 1 5 2 1 2 4 3 3 3 2 5 2 4 1 4 3 2 2 5 5 1 1 3 3 2 2 2 2 1 0 0 0 0 0 0.124000 2.700 2.700 7.000 925764 3 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 2 1 3 0 1 1 0 0 0 0 0 1 1 1 1 0 0 0 1 1 0 1 2 0 0 3 2 0 1 2 1 1 2 0 2 1 2 2 0 0 2 3 2 3 2 2 3 2 2 4 0 2 0 5 1 3 2 3 1 2 3 2 0 6 4 3 6 2 5 0 5 2 1 4 4 5 7 4 2 3 5 2 0 2 5 2 4 7 4 4 4 8 5 3 1 7 2 2 1 5 5 5 14 19 16 22 18 30 29 25 36 23 23 22 25 25 27 26 23 14 20 16 16 10 6 6 6 4 2 6 6 6 6 6 4 6 1 0 3 4 4 5 2 4 3 2 4 4 5 5 5 6 10 6 3 6 8 5 5 8 7 4 6 4 3 4 8 5 5 7 4 6 3 5 8 4 3 4 4 3 4 3 1 3 3 7 2 4 8 3 6 4 3 3 2 5 4 4 3 7 4 5 4 4 3 4 7 2 3 3 4 3 0 2 2 4 3 4 2 4 2 2 6 4 4 6 6 1 5 1 1 2 1 0 0 0 0 0 0.126000 2.750 2.750 7.100 969560 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 1 1 0 1 2 0 2 0 2 2 0 1 1 1 0 0 1 0 1 1 1 1 2 0 1 2 2 1 2 0 0 1 0 1 0 2 1 0 1 0 1 1 2 0 3 0 3 4 3 1 3 2 0 4 0 1 2 0 3 1 1 2 3 2 2 2 5 1 7 1 5 1 5 4 2 0 0 1 2 1 3 2 3 3 5 4 10 10 2 5 11 4 1 2 1 7 3 5 4 4 1 5 10 8 7 9 9 20 20 21 33 21 28 20 27 32 21 29 22 20 24 15 13 27 14 13 15 10 9 3 11 6 7 5 3 6 8 5 4 4 1 3 3 5 2 7 3 6 6 1 6 4 6 5 3 4 2 4 3 3 9 4 5 4 4 5 2 3 10 4 3 2 6 10 6 3 6 5 5 5 4 8 8 5 4 3 6 4 4 2 4 4 4 5 7 4 4 4 4 5 2 2 3 4 5 2 1 3 2 6 2 7 7 1 6 4 4 6 5 5 4 0 2 2 3 2 7 5 0 4 1 1 4 6 1 0 3 2 0 0 1 0.128000 2.800 2.800 7.200 1022713 5 0 0 0 0 0 0 0 0 0 0 0 0 1 0 2 0 0 0 1 0 1 1 0 0 1 1 1 0 0 0 2 1 0 0 4 0 0 1 2 3 1 1 0 1 0 1 0 3 1 1 1 2 2 1 1 1 3 1 0 2 4 2 1 2 1 2 0 3 1 3 2 1 5 2 1 3 1 2 1 5 3 2 1 2 5 3 8 2 3 2 5 5 4 3 6 4 4 4 3 2 3 8 4 3 4 5 4 5 4 7 6 5 3 3 3 5 2 9 10 7 9 12 11 13 17 15 22 19 33 24 28 30 26 21 24 22 27 20 26 16 10 10 9 20 10 7 4 5 7 7 2 7 5 3 5 1 6 1 5 7 5 6 3 1 5 1 1 3 4 8 6 3 9 5 5 3 6 7 4 6 7 6 4 2 4 6 2 3 6 5 6 7 6 4 4 9 6 8 6 9 7 1 2 6 2 7 5 4 4 4 4 5 5 4 4 3 6 3 5 3 6 4 3 6 6 2 5 2 8 4 5 3 6 5 4 5 8 4 3 5 6 5 5 2 8 1 2 2 5 4 1 3 0 0 0 0 0 0.130000 2.850 2.850 7.300 1081669 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 5 0 0 2 2 0 0 1 0 0 0 1 1 0 2 0 2 2 2 1 0 1 0 2 2 3 1 1 0 2 0 1 0 2 1 1 2 2 0 1 4 3 0 2 1 1 0 2 5 2 1 0 1 3 2 5 2 1 2 5 2 3 4 3 6 6 6 4 6 6 3 1 3 2 3 4 7 5 2 9 7 4 1 4 4 3 2 2 2 7 4 8 4 7 4 6 8 5 1 8 6 10 18 21 18 15 21 24 21 26 22 30 28 27 23 22 21 17 25 20 17 13 17 9 12 7 8 5 4 4 5 5 2 4 1 1 2 5 7 6 4 9 7 7 5 5 5 5 5 2 4 5 3 6 8 2 4 9 4 10 5 1 4 5 5 5 10 3 2 8 6 5 7 3 13 3 3 6 5 1 4 5 9 5 2 7 4 5 6 3 5 6 5 4 5 9 6 4 3 4 4 4 5 8 5 5 0 3 6 3 4 3 7 5 6 4 3 3 6 8 4 1 3 1 2 7 3 4 6 6 1 3 4 1 0 1 0 0 0.132000 2.900 2.900 7.400 1131887 3 0 0 0 0 0 0 0 0 0 1 0 0 1 2 1 1 0 0 0 1 2 2 1 1 0 2 1 1 0 1 1 1 0 2 2 3 1 0 1 0 1 0 2 0 2 0 1 4 0 1 2 2 0 0 0 2 3 0 1 2 3 0 1 2 3 5 6 2 2 3 1 4 4 8 4 3 3 3 7 2 2 5 7 4 1 2 4 8 1 5 2 7 3 4 2 9 6 5 5 6 2 2 3 6 2 5 6 7 7 2 8 3 3 3 3 6 6 5 3 10 15 15 17 19 13 29 20 23 22 34 28 28 33 20 20 22 17 22 18 15 19 14 11 9 13 6 6 13 4 2 9 8 8 7 6 5 6 4 4 9 6 2 8 9 7 2 6 3 7 3 6 3 7 4 4 5 4 5 6 4 7 5 4 10 2 6 6 8 3 6 6 9 5 8 8 7 6 4 8 5 7 5 5 7 3 5 5 5 10 7 3 8 7 5 7 2 4 4 6 4 10 7 6 4 4 4 4 3 2 4 2 6 5 9 7 3 2 6 2 5 1 5 6 2 2 1 9 2 5 2 5 1 0 0 0 1 1 0.134000 2.950 2.950 7.500 1185706 3 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 3 2 1 0 1 1 0 0 0 0 0 1 0 1 1 2 0 1 0 1 2 0 0 0 1 1 0 1 1 1 0 2 2 0 1 3 3 2 3 0 0 2 2 3 2 1 1 3 0 0 1 1 3 4 3 1 1 9 1 4 0 1 3 4 1 3 2 6 4 7 7 3 2 8 5 2 5 2 4 6 7 3 7 7 8 4 7 2 4 7 7 9 9 2 5 5 8 3 5 7 3 6 10 6 10 15 10 13 14 29 21 23 37 26 20 28 20 16 24 25 16 19 21 20 20 17 11 10 12 8 7 7 5 5 5 4 5 6 7 3 6 5 7 5 11 9 6 8 11 6 4 6 8 8 7 7 7 4 5 4 8 5 4 3 4 8 10 7 9 4 7 6 8 9 7 3 5 7 7 6 2 6 4 7 3 9 8 12 7 6 6 6 4 5 7 2 4 7 3 2 4 4 7 1 4 5 0 4 6 3 10 8 5 4 3 4 5 7 5 7 5 7 3 5 2 5 6 4 5 2 4 1 6 6 2 4 2 0 0 1 0 0.136000 3.000 3.000 7.600 1238426 3 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 2 4 0 2 0 2 2 0 1 1 1 0 2 1 1 2 1 0 1 1 0 3 1 0 0 1 0 1 0 0 2 1 1 0 4 0 2 6 3 3 4 0 3 1 2 4 0 4 4 0 1 5 2 2 5 1 3 4 3 3 5 2 4 4 6 2 5 3 4 5 4 5 6 7 5 6 2 8 3 4 7 2 4 4 3 7 6 5 1 4 8 3 7 10 3 3 6 1 5 3 8 11 5 7 15 11 15 17 21 23 21 24 28 16 21 29 15 22 27 28 20 13 19 13 7 15 10 11 9 6 8 8 4 7 5 4 6 5 10 6 7 8 9 3 5 5 9 5 9 4 4 4 3 5 7 4 10 6 8 4 9 8 4 6 7 9 11 6 8 3 5 8 12 3 6 9 7 11 9 6 7 4 7 7 7 2 5 4 5 0 2 9 5 5 5 10 7 5 6 3 9 4 4 13 2 7 5 7 4 7 2 0 4 5 4 4 6 8 1 2 5 6 4 7 3 11 4 3 3 5 5 4 4 3 1 4 2 2 1 1 0 0.138000 3.050 3.050 7.700 1299809 6 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 1 2 1 1 0 0 1 0 0 2 0 1 2 0 0 3 0 0 1 3 1 2 0 2 0 1 1 2 1 2 3 2 1 2 5 2 2 2 4 3 2 5 3 0 3 2 4 5 4 3 0 5 4 1 4 3 8 6 4 4 7 4 5 4 3 6 5 6 10 3 6 6 2 6 3 4 4 3 6 7 6 8 3 4 7 5 4 9 2 4 8 5 9 8 3 7 5 7 7 13 7 11 15 17 16 18 18 18 20 17 26 25 19 20 26 31 22 18 20 18 14 11 16 4 7 11 10 8 9 9 6 3 8 8 7 5 6 10 3 5 6 6 3 12 7 8 8 2 10 4 13 9 9 12 4 5 9 7 9 5 7 4 8 9 6 7 8 10 8 7 5 7 11 6 4 4 4 6 4 9 4 5 9 10 7 4 12 7 4 9 5 10 10 6 8 4 7 2 4 7 2 6 8 4 11 3 3 9 7 6 7 3 8 7 4 8 5 3 7 4 5 5 7 4 6 7 5 5 3 5 2 5 4 1 2 0 0 1 0.140000 3.100 3.100 7.800 1361810 3 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 3 2 1 0 0 0 1 1 1 2 0 0 0 0 1 0 2 2 2 1 0 0 3 3 0 2 0 6 2 3 1 0 3 3 1 2 2 5 3 5 3 3 2 2 7 3 2 2 3 4 2 3 4 4 1 3 7 4 5 4 2 3 5 4 2 1 3 6 3 4 3 8 7 6 5 3 5 11 5 5 3 3 7 3 6 4 4 2 4 4 4 1 5 5 9 6 6 9 3 10 8 6 8 3 10 8 16 16 13 18 23 29 25 19 19 20 27 19 22 27 24 21 15 18 11 20 21 17 12 5 18 6 12 7 9 11 7 12 11 4 8 8 4 8 7 7 2 6 4 4 9 6 9 3 4 7 7 7 4 10 4 11 5 8 8 8 5 4 4 8 6 4 9 8 12 12 8 5 8 3 10 8 7 5 3 5 6 8 5 6 10 7 2 11 2 5 5 6 8 10 2 7 5 5 14 2 7 3 9 3 5 2 8 2 3 4 4 7 9 5 4 7 6 7 5 6 3 5 4 7 6 7 7 9 3 0 2 1 1 1 0 0 0.142000 3.150 3.150 7.900 1429499 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 1 2 1 1 0 0 0 3 0 2 2 1 0 3 0 2 1 3 0 0 1 1 3 1 2 4 1 5 3 5 1 0 7 1 3 2 3 2 2 2 3 0 0 1 3 6 3 2 2 4 4 4 6 4 3 6 4 10 3 7 2 5 4 7 4 5 8 4 7 4 1 7 11 5 2 10 2 11 3 7 8 10 9 6 3 5 3 6 3 10 11 5 5 9 7 10 8 9 5 15 11 9 18 18 15 24 17 23 17 19 25 17 24 18 37 16 17 21 17 14 20 17 15 15 9 4 11 7 3 8 10 8 8 6 8 3 4 5 8 4 6 3 9 9 6 2 10 4 4 3 8 4 9 1 7 5 9 7 10 9 10 4 6 5 8 6 6 10 10 6 5 7 6 6 10 5 7 8 8 8 7 7 11 12 8 3 10 6 9 13 11 4 6 7 6 3 10 5 8 4 7 7 7 5 8 4 9 5 5 7 6 6 7 11 11 7 8 5 3 5 7 7 10 3 3 6 5 7 9 2 3 7 1 0 0 0 0 1 0.144000 3.200 3.200 8.000 1493946 3 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 2 3 0 0 1 2 1 1 1 4 1 0 1 0 1 2 1 3 1 1 1 1 2 1 1 3 2 6 0 4 0 1 4 2 4 5 2 1 3 0 2 2 4 2 3 2 4 3 5 4 4 4 1 5 1 3 4 5 6 4 7 2 8 8 8 5 3 6 0 7 3 2 2 5 7 5 7 5 8 9 6 4 3 6 8 6 10 2 5 6 3 3 6 6 6 6 17 5 10 6 6 11 11 13 12 21 26 18 24 21 24 23 30 18 22 20 24 19 13 17 25 22 17 15 8 13 7 10 8 9 6 7 9 8 7 8 9 7 7 6 12 5 9 9 12 9 12 6 9 7 10 7 7 4 9 7 4 2 7 4 5 8 8 9 7 6 7 5 9 4 8 13 6 5 4 7 9 6 7 7 9 4 4 5 8 10 9 10 6 6 7 9 12 11 8 8 9 11 5 8 7 5 5 8 5 9 10 5 5 11 11 6 8 8 4 8 5 5 5 4 7 4 5 6 5 6 6 7 7 4 2 6 3 2 1 0 0 0 0 0 0.146000 3.250 3.250 8.100 1562352 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 0 2 0 1 2 1 1 0 0 1 0 1 2 0 0 0 3 1 2 0 4 4 2 0 0 2 3 2 0 1 3 3 4 0 1 4 3 3 4 5 5 4 2 1 4 2 5 3 2 7 6 3 5 6 5 5 5 1 5 2 7 4 8 7 4 6 5 7 5 3 5 8 1 6 4 6 8 7 6 7 6 3 4 6 3 5 8 4 10 3 3 11 6 5 3 9 6 4 3 17 9 11 11 24 13 15 14 25 26 26 21 17 32 32 22 18 25 29 29 27 24 21 12 23 14 12 11 9 17 7 9 11 3 7 6 5 5 12 3 6 8 7 4 7 11 10 8 9 5 8 2 10 9 8 10 10 7 7 4 7 5 7 7 9 10 8 7 7 16 6 8 10 5 6 6 12 12 7 11 11 8 9 7 8 12 10 7 8 7 11 8 9 7 7 4 9 4 7 14 9 8 8 13 9 8 7 13 5 9 5 7 4 9 5 7 8 7 8 7 3 10 9 3 4 4 4 5 2 6 6 3 5 10 4 4 2 3 0 1 0 0 0.148000 3.300 3.300 8.200 1630559 3 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 4 2 1 1 1 2 1 2 0 2 1 5 0 1 1 4 0 2 1 4 5 3 0 1 1 1 2 1 3 3 3 1 1 1 1 1 3 4 6 6 8 8 4 3 2 7 2 2 1 7 4 4 5 1 10 6 4 4 4 3 3 3 6 11 6 4 5 4 8 5 5 9 4 5 5 7 6 4 13 12 3 6 7 5 2 7 9 7 8 8 4 7 6 4 10 6 8 9 9 9 13 15 17 23 25 13 16 24 22 26 21 27 24 24 21 21 21 15 17 22 25 21 22 17 14 11 8 12 5 9 7 8 5 11 10 6 6 5 9 13 10 9 8 8 8 6 4 9 10 9 9 7 8 7 5 7 8 14 13 5 14 5 12 11 8 9 6 5 4 9 13 7 10 13 11 11 8 5 9 10 8 7 6 7 13 3 13 8 7 13 17 5 8 5 10 7 12 7 6 6 9 7 8 8 11 8 11 9 11 11 8 5 6 10 4 9 3 10 8 7 10 8 7 8 10 10 7 4 11 5 7 8 2 4 3 0 0 1 0 1 0.150000 3.350 3.350 8.300 1707576 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 2 1 2 1 0 2 0 2 3 1 3 2 2 2 2 0 2 1 4 3 2 2 3 1 2 1 0 2 2 4 2 5 3 3 5 2 8 4 5 4 2 3 6 7 6 1 0 7 4 7 7 6 5 4 3 4 6 6 7 6 2 7 4 4 2 5 5 6 9 3 3 3 6 6 5 3 5 7 8 8 6 8 8 6 8 3 9 6 6 8 8 6 4 8 6 6 10 4 11 6 11 15 23 16 8 17 20 21 19 24 15 14 19 21 30 25 21 15 19 16 18 21 21 15 14 12 16 8 10 12 7 10 9 8 10 10 7 9 8 10 12 6 6 9 11 6 5 9 12 6 7 12 7 5 6 8 5 9 4 11 9 8 8 10 7 6 10 7 11 13 7 4 13 11 8 11 9 16 6 12 11 10 10 19 2 9 11 8 7 8 8 6 13 6 10 12 12 9 12 9 9 8 7 7 9 6 12 8 4 9 9 8 5 7 8 9 5 12 5 7 5 9 10 9 10 3 6 6 8 7 11 3 5 5 4 2 0 0 0 0 0.152000 3.400 3.400 8.400 1777231 3 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 1 1 3 1 0 3 4 2 3 3 3 3 3 2 1 1 1 1 3 3 0 1 8 0 0 5 3 7 4 4 4 4 4 3 5 2 2 5 3 6 1 7 6 1 2 2 5 2 1 6 6 8 7 7 5 10 4 1 6 9 3 4 5 3 5 8 4 9 8 11 8 3 2 7 7 9 10 9 10 8 6 8 6 8 7 10 8 7 3 8 4 10 7 6 8 9 6 5 16 9 19 24 23 17 23 24 22 30 21 15 23 27 20 20 20 18 20 23 18 17 15 19 17 18 13 9 4 4 7 12 7 10 4 8 6 10 5 6 13 2 3 8 7 8 7 3 11 8 7 9 7 19 7 8 9 6 14 8 8 11 10 11 13 14 10 16 8 9 13 8 9 9 12 7 12 11 6 9 15 5 9 9 9 11 11 13 6 10 6 4 12 9 9 12 11 8 6 9 16 10 10 10 8 10 10 6 7 4 1 15 6 8 4 9 13 11 8 10 11 9 8 3 3 6 6 7 9 4 6 8 7 4 2 1 2 2 1 0 0.154000 3.450 3.450 8.500 1849489 6 0 0 0 0 0 0 0 0 0 0 0 1 1 3 0 1 2 2 0 1 4 1 1 0 1 0 2 1 0 0 1 1 1 1 6 3 6 1 3 1 3 3 0 6 0 4 2 7 4 6 4 4 3 7 4 5 7 5 5 2 3 9 9 2 5 5 3 9 4 2 7 6 2 8 2 5 7 12 6 5 4 5 10 4 12 10 6 4 14 7 9 10 11 7 7 7 7 3 9 7 4 3 8 7 5 7 9 6 8 9 6 8 8 12 6 5 11 12 13 11 13 21 26 19 23 25 18 23 22 23 23 18 27 20 15 20 25 24 19 18 12 14 13 15 8 15 10 11 7 9 13 11 12 13 11 11 7 11 13 6 5 10 6 6 10 8 14 5 14 11 8 5 9 7 10 10 8 7 15 13 3 13 12 18 15 7 10 9 10 8 15 9 6 8 9 10 10 9 5 7 7 5 10 11 13 12 12 12 10 6 17 10 11 9 4 8 7 6 6 9 12 8 16 18 7 5 10 8 12 10 15 6 13 11 6 10 16 10 11 16 8 9 5 11 10 14 11 5 2 5 7 3 1 1 0 1 0 0.156000 3.500 3.500 8.600 1920727 4 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 2 1 2 0 3 0 1 1 0 1 0 3 0 4 4 1 3 1 2 3 3 4 3 1 2 3 9 5 2 3 7 3 3 6 5 2 6 1 4 3 2 3 6 5 1 8 3 8 5 3 7 6 13 11 9 5 8 7 7 5 8 7 4 8 6 4 10 4 6 5 6 9 9 12 6 7 10 9 9 8 8 3 8 9 8 8 2 12 11 13 8 13 7 8 6 6 9 6 8 16 13 14 16 16 22 20 21 21 17 20 18 19 22 20 11 20 22 21 14 19 15 23 17 15 12 14 19 16 10 11 14 11 9 11 9 12 8 16 14 9 6 18 10 11 7 10 11 17 10 13 8 10 12 9 12 7 7 10 10 11 11 9 8 8 14 10 10 9 14 9 14 13 9 19 16 17 4 11 8 12 11 10 21 6 10 8 9 12 9 7 7 12 7 16 14 10 13 6 13 8 9 10 6 10 8 7 10 4 6 11 19 12 6 7 5 8 11 10 12 13 9 6 10 5 11 11 4 14 10 7 2 6 5 1 2 5 1 1 0 0 0.158000 3.550 3.550 8.700 1999833 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 2 3 2 2 2 1 2 3 0 1 0 1 3 2 0 0 3 2 3 2 5 7 0 3 4 1 10 7 7 4 5 2 3 4 3 8 3 6 4 4 4 8 2 3 4 5 5 7 1 6 7 8 1 6 8 1 4 4 11 9 4 7 11 9 10 5 6 8 4 3 9 7 9 11 5 5 8 8 4 8 7 8 11 9 12 6 4 13 4 12 10 6 9 11 10 11 10 11 11 11 14 15 14 23 18 17 29 16 26 23 15 19 14 18 19 22 31 13 21 20 12 16 15 14 18 17 15 8 12 14 13 10 10 10 10 10 13 11 6 8 11 8 14 8 10 11 11 8 10 13 5 14 7 12 9 10 10 12 15 18 8 6 9 9 12 8 9 20 14 16 10 11 14 5 5 13 6 11 9 11 15 6 9 13 11 7 8 7 10 8 16 12 11 8 10 14 11 17 11 8 16 13 9 10 5 10 17 13 14 16 8 10 9 11 5 10 9 10 12 8 11 12 11 8 6 7 12 15 13 12 7 13 5 0 3 2 0 0 0 0 0.160000 3.600 3.600 8.800 2073149 3 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 2 1 2 1 2 2 1 0 2 2 1 0 3 6 4 5 5 2 2 2 5 5 3 6 4 6 4 5 2 4 4 3 2 4 6 3 3 6 5 7 4 5 7 5 3 5 6 13 5 3 10 5 9 7 4 5 6 5 10 6 5 5 6 6 4 14 7 6 11 6 9 10 9 8 5 3 8 10 10 6 6 8 9 5 6 14 7 11 10 9 9 11 13 8 4 5 10 12 6 16 8 8 7 19 20 23 10 16 27 25 23 19 26 21 16 20 21 24 18 25 8 11 13 16 18 13 22 18 9 16 4 16 10 12 13 9 7 9 8 17 11 10 13 10 14 4 9 12 16 8 9 16 17 13 11 14 8 8 13 9 11 15 10 11 14 8 6 4 9 11 18 9 9 8 9 15 11 11 11 9 6 13 13 10 7 8 10 15 14 9 7 4 10 12 17 10 14 13 10 10 12 20 9 7 6 11 15 11 10 8 9 6 10 13 17 6 8 9 6 13 13 16 10 15 5 11 14 11 12 6 5 12 9 4 9 2 4 1 1 0 0 0 0.162000 3.650 3.650 8.900 2156456 5 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 2 0 1 1 3 2 3 4 3 3 2 1 3 6 5 2 3 4 4 3 6 2 3 4 4 5 5 3 4 1 4 5 9 3 3 4 3 3 8 5 6 12 2 10 3 4 6 8 9 8 8 2 2 7 5 8 2 8 9 7 2 6 8 6 5 8 2 7 5 6 13 5 6 8 11 6 10 5 6 3 8 10 11 10 10 14 10 11 8 11 8 12 6 12 5 15 12 13 10 13 13 18 23 12 21 18 21 23 20 30 20 23 26 24 24 21 21 29 19 21 16 23 20 13 19 13 16 11 15 13 13 11 8 11 14 14 13 4 16 15 18 13 9 19 8 11 6 9 14 8 13 12 13 10 13 10 14 11 13 11 8 10 13 11 11 14 11 8 14 11 10 9 14 12 14 18 8 12 7 13 12 10 14 14 8 12 17 11 13 9 12 12 15 7 9 13 17 11 11 11 12 17 12 11 16 15 8 9 12 7 13 15 11 16 7 10 7 14 5 18 10 10 8 8 6 6 13 14 6 9 11 9 9 3 5 1 1 3 0 0 0.164000 3.700 3.700 9.000 2234753 3 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 4 1 4 2 1 3 1 1 3 2 3 3 1 3 6 2 4 4 3 3 3 6 5 2 6 4 1 3 3 7 1 4 4 6 12 4 5 2 6 4 9 3 1 8 11 5 2 7 6 3 8 4 7 3 8 3 9 6 7 8 9 2 7 6 9 6 15 6 9 5 9 4 9 17 15 10 2 10 6 8 12 12 11 12 10 9 7 11 8 7 5 11 10 14 16 7 7 7 13 15 10 16 17 21 19 14 18 24 19 27 27 24 20 22 24 21 20 14 24 17 17 18 32 15 12 13 15 12 8 14 11 11 19 11 14 15 18 10 5 12 11 11 9 15 9 7 9 16 12 9 12 10 15 9 18 7 11 12 14 7 20 8 10 13 14 11 6 6 9 11 8 10 16 8 17 13 17 9 16 11 10 9 13 20 17 14 12 10 13 11 9 9 17 20 10 16 8 14 13 14 18 15 15 8 10 12 11 22 12 13 9 12 9 11 14 19 12 12 8 8 12 11 19 11 11 12 15 11 15 13 9 9 10 9 4 9 4 2 1 0 0 0.166000 3.750 3.750 9.100 2327990 3 0 0 0 0 0 0 0 0 0 0 0 0 0 3 2 2 0 1 2 2 1 1 0 0 3 1 4 2 6 4 2 4 3 2 5 5 2 3 1 3 1 2 10 2 7 4 3 4 3 3 4 3 10 6 9 6 3 8 5 5 3 4 4 6 8 4 4 7 5 5 11 14 5 3 6 8 8 7 10 11 7 17 7 11 10 8 7 8 12 13 11 12 6 13 9 7 7 6 5 8 13 10 10 14 11 11 8 12 15 14 9 13 10 9 18 13 18 12 23 14 17 24 15 23 25 31 19 17 29 19 19 19 26 25 19 17 22 19 19 19 11 11 12 22 21 8 10 18 10 14 19 17 13 14 10 6 9 10 15 11 5 13 13 11 11 17 16 9 7 14 7 19 6 10 13 7 12 18 14 7 12 15 13 13 9 13 13 13 12 12 14 12 19 10 16 18 18 12 8 10 10 9 7 14 9 11 13 12 8 15 12 11 10 12 11 17 15 19 14 14 12 7 7 12 11 15 16 12 11 12 10 19 19 12 14 12 15 11 20 13 7 18 9 15 19 16 11 5 9 8 6 2 4 0 2 0 1 0.168000 3.800 3.800 9.200 2406866 3 0 0 0 0 0 0 0 0 0 0 1 0 2 0 1 0 2 3 2 3 1 2 1 2 2 5 2 1 2 3 2 2 2 5 3 5 3 3 1 3 6 8 6 1 3 9 6 3 6 10 5 5 7 4 5 7 12 9 5 7 5 6 6 8 3 5 4 7 8 5 6 5 8 13 4 10 2 10 9 7 7 16 9 10 9 13 8 12 9 13 15 9 15 9 10 11 6 6 6 7 7 6 8 15 9 8 9 6 12 12 11 14 12 11 13 8 17 18 18 11 14 19 14 25 21 15 10 15 19 27 23 22 24 17 19 18 12 16 22 21 25 9 25 15 19 15 21 15 8 11 13 12 10 12 7 13 11 17 11 13 10 16 19 14 23 11 8 12 13 10 9 17 4 14 10 7 10 17 14 11 11 20 18 13 8 12 6 8 13 12 23 15 14 15 16 9 14 9 13 14 17 11 17 11 10 15 17 11 6 12 12 14 15 17 12 16 16 8 17 15 15 10 15 11 10 15 12 13 9 12 9 12 15 12 6 18 7 15 14 12 21 18 11 10 18 11 19 11 7 11 3 2 5 4 0 1 1 0.170000 3.850 3.850 9.300 2508471 7 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 1 2 1 4 3 3 1 2 7 0 3 2 2 2 2 5 2 3 2 3 3 4 3 7 3 5 3 4 4 6 2 3 10 4 11 3 13 7 7 5 6 3 8 10 6 6 4 10 11 4 12 7 8 9 7 7 8 4 6 7 9 9 5 9 11 5 14 9 10 7 9 8 8 5 6 11 13 14 10 10 10 10 8 9 9 9 9 14 14 13 11 8 18 9 10 9 16 12 13 15 13 10 17 16 20 14 22 20 26 29 29 27 24 20 37 21 24 13 18 13 28 24 22 25 21 13 14 15 9 11 18 8 16 17 16 13 12 16 11 11 17 15 11 15 10 11 12 13 12 12 20 15 14 15 16 12 17 15 15 12 10 14 14 17 15 19 15 13 13 11 12 16 14 17 16 8 16 12 8 14 13 13 10 10 9 12 11 19 20 13 11 4 15 11 14 11 20 18 18 13 20 12 20 21 15 15 12 13 18 18 11 16 9 14 9 18 11 10 11 20 11 13 17 13 13 12 14 16 10 12 12 23 12 11 12 8 8 1 0 1 2 0 0.172000 3.900 3.900 9.400 2591210 3 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 4 4 3 2 1 3 3 2 3 0 3 6 1 3 1 5 5 4 3 9 9 0 4 7 5 3 5 5 8 7 3 3 5 5 8 5 11 10 8 10 3 6 6 6 7 7 8 8 12 9 6 10 8 7 10 8 8 10 4 6 12 20 4 6 11 7 9 10 7 5 10 6 12 11 7 13 13 16 12 6 8 14 13 9 7 5 14 17 17 10 12 11 6 13 11 17 3 23 13 21 12 21 28 11 23 30 28 23 24 26 26 17 21 15 27 23 33 16 22 25 11 20 22 23 21 20 7 21 13 16 12 16 16 13 18 18 9 13 16 15 9 20 13 19 15 8 9 11 14 13 10 9 10 16 15 14 17 15 19 16 12 14 12 14 14 16 19 19 4 24 8 12 15 16 11 15 14 20 14 13 13 14 16 19 14 13 19 14 18 23 15 15 4 14 17 14 8 10 15 20 11 15 19 12 9 13 12 11 16 12 16 13 14 16 13 16 16 19 19 12 11 10 19 15 15 14 12 5 11 18 17 10 13 12 9 6 2 0 0 1 0 0.174000 3.950 3.950 9.500 2675515 3 0 0 0 0 0 0 0 0 0 0 0 2 0 1 1 0 2 1 2 3 3 1 3 1 3 7 5 3 6 4 3 9 4 5 2 5 3 3 3 6 9 5 5 2 6 8 5 8 4 8 5 6 5 6 4 6 3 7 11 6 9 9 3 6 6 7 6 8 7 9 12 18 6 9 8 11 11 8 14 15 15 11 15 13 9 19 10 15 14 9 4 18 5 8 10 8 10 13 9 12 11 8 8 12 6 15 8 9 9 18 7 17 21 9 13 18 14 21 24 18 22 17 26 15 21 23 25 19 26 23 20 27 17 27 20 26 15 22 15 19 15 16 24 12 15 24 13 13 17 11 7 10 21 15 15 16 13 20 22 12 16 12 16 15 14 18 11 12 14 14 24 10 13 16 19 8 11 18 19 15 15 23 16 16 11 12 18 11 13 14 16 10 14 13 18 12 15 15 14 8 11 17 12 22 13 12 14 15 10 11 15 19 15 12 17 8 21 23 13 19 11 8 12 15 11 14 15 19 15 10 17 9 16 14 18 14 16 14 14 23 14 14 13 16 12 14 15 14 9 14 7 5 2 3 1 1 1 0.176000 4.000 4.000 9.600 2779386 5 0 0 0 0 0 0 0 0 0 0 0 0 2 2 3 0 1 3 0 6 2 6 3 1 5 0 4 1 6 5 1 6 3 6 5 6 2 5 4 5 3 9 8 5 7 5 8 4 12 8 12 6 8 5 7 5 7 10 5 5 6 7 9 7 10 7 10 10 8 12 10 6 13 10 11 12 11 10 10 16 9 6 12 9 11 17 10 11 10 14 11 16 7 11 13 12 10 17 14 11 13 12 10 13 16 16 17 17 15 14 11 8 15 13 27 22 14 19 17 22 22 27 18 28 19 27 32 24 33 21 17 23 12 27 25 20 20 17 22 14 15 22 21 14 9 16 12 19 16 17 16 16 20 14 18 15 14 18 10 12 9 16 12 12 10 13 19 12 12 15 14 15 22 12 11 15 18 19 18 10 6 11 14 10 23 17 14 16 19 10 10 16 19 17 23 16 18 19 18 16 12 14 14 14 13 11 10 24 21 22 26 18 18 18 14 17 5 13 17 11 13 16 14 18 16 9 15 15 18 16 14 21 13 22 17 9 8 16 17 16 16 19 7 20 19 18 16 10 6 10 6 3 5 1 0 0 2 0.178000 4.050 4.050 9.700 2869617 3 0 0 0 0 0 0 0 0 0 0 0 2 2 2 0 1 4 1 3 2 2 1 2 3 2 2 4 4 7 5 6 5 3 6 6 5 7 8 1 5 2 3 5 5 8 10 7 6 10 9 6 8 9 7 8 10 15 4 10 5 8 8 6 11 8 8 11 7 5 8 14 5 11 7 13 10 9 7 8 9 14 12 10 9 11 6 14 15 14 13 11 9 18 18 10 14 14 10 12 16 12 9 8 14 15 6 11 11 12 10 14 12 11 18 13 13 27 16 23 23 20 21 32 20 18 25 22 24 32 25 34 19 23 21 25 22 25 19 23 19 21 16 19 16 18 9 18 6 13 12 13 18 12 8 19 14 14 11 16 13 15 14 21 11 14 14 13 11 20 14 14 26 10 22 16 18 15 20 24 18 19 19 16 14 14 14 21 13 19 18 20 13 17 11 17 14 22 17 15 15 20 8 21 15 16 16 23 17 13 19 21 20 12 15 18 15 19 15 18 17 20 15 13 14 24 18 15 15 14 18 20 19 17 19 20 21 21 15 19 19 17 11 16 16 11 23 10 20 13 10 5 10 2 3 1 1 0 0.180000 4.100 4.100 9.800 2975040 3 0 0 0 0 0 0 0 0 0 1 0 0 1 2 2 4 4 2 4 4 1 2 5 0 3 3 5 2 5 5 4 9 2 7 8 4 8 3 11 6 10 4 7 8 6 6 5 8 8 7 11 4 4 11 12 7 11 7 10 11 7 11 11 10 9 7 13 12 18 8 14 12 14 12 8 8 16 10 10 14 16 10 6 8 15 15 15 22 13 19 18 12 6 11 10 7 12 12 24 15 17 9 17 21 10 17 18 14 14 14 9 22 11 23 17 15 23 32 20 11 12 20 15 23 30 20 25 19 26 29 19 27 23 15 19 11 30 16 21 24 18 18 14 8 6 25 13 21 13 13 19 13 21 25 23 18 14 14 13 20 12 14 8 10 25 14 15 20 15 10 15 16 21 8 15 20 21 20 13 16 15 20 11 18 17 17 9 12 24 19 13 18 17 20 14 15 20 10 23 19 25 8 7 13 14 11 15 18 13 10 12 10 17 11 24 16 17 11 12 13 16 20 14 26 12 17 13 14 16 16 6 20 16 23 22 11 17 16 14 25 19 17 21 22 19 13 19 16 18 10 11 7 4 6 0 0 2 0.182000 4.150 4.150 9.900 3083416 6 0 0 0 0 0 0 0 0 0 0 0 2 1 1 4 1 3 4 3 5 6 2 1 4 2 3 5 6 6 7 2 4 1 11 7 5 2 6 6 8 9 8 12 7 11 9 6 12 7 8 9 6 6 8 11 6 6 8 11 8 11 12 11 13 9 10 7 9 6 11 9 13 12 12 8 14 15 8 9 8 8 11 22 16 6 11 16 15 9 13 12 12 13 11 15 9 9 16 14 14 12 21 12 12 12 16 19 10 15 18 8 16 14 16 16 21 30 22 9 25 19 19 26 23 33 25 22 21 19 21 20 20 21 20 26 20 29 27 25 25 21 20 25 21 21 18 14 19 15 6 20 18 16 20 16 13 13 15 15 15 15 22 16 15 15 11 21 19 11 19 13 14 15 17 21 12 18 12 22 18 21 18 13 23 15 18 9 21 11 14 23 18 21 25 18 22 15 21 23 15 15 16 19 21 18 19 21 17 13 24 23 22 19 14 20 22 15 14 14 20 20 23 13 18 15 18 20 20 24 9 12 17 21 21 12 16 17 16 16 21 26 19 15 21 22 24 15 11 13 13 6 8 1 4 0 1 0 0.184000 4.200 4.200 10.00 3174897 3 0 0 0 0 0 0 0 0 0 0 0 1 1 2 3 0 5 4 3 3 0 7 3 2 4 2 8 6 4 5 9 3 8 6 4 2 7 6 8 7 9 3 5 8 5 9 7 7 6 11 14 7 12 9 9 5 15 12 14 15 12 9 11 5 8 13 11 12 10 9 17 12 11 8 17 11 19 11 15 9 11 7 15 14 16 16 16 7 12 10 14 13 13 16 16 11 15 13 14 12 16 11 12 13 17 10 13 19 11 17 11 13 14 13 10 19 19 23 24 22 24 24 31 19 23 22 28 21 25 29 17 23 17 21 30 22 19 25 27 27 22 23 23 17 25 17 20 17 12 23 21 9 17 20 16 19 16 17 20 9 16 11 22 16 15 12 15 17 23 24 16 16 18 26 11 16 20 18 10 14 17 26 19 17 15 17 19 12 21 20 24 17 27 13 16 18 19 23 14 19 14 10 11 18 19 6 15 21 23 25 17 17 18 21 27 20 17 18 20 25 22 20 18 22 18 17 15 24 16 15 22 18 22 14 20 20 22 18 22 25 19 26 12 19 19 13 12 16 19 14 9 7 5 4 2 0 2 0.186000 4.250 4.250 10.10 3283256 3 0 0 0 0 0 0 0 0 1 0 0 1 1 4 1 5 2 5 5 3 4 6 3 2 4 7 8 2 6 6 4 10 7 8 7 5 4 4 9 8 18 10 7 6 6 13 12 10 13 10 7 15 4 7 10 13 12 8 8 13 5 14 6 9 14 9 10 16 12 13 11 8 12 11 10 13 9 11 15 17 23 18 13 10 12 11 12 14 14 14 10 12 12 16 13 15 13 13 14 18 10 13 17 14 14 14 12 12 8 18 14 23 20 16 19 16 16 16 27 18 21 19 20 19 37 22 21 22 28 24 26 18 21 28 21 22 21 21 22 16 15 13 22 22 27 22 11 13 20 10 17 16 19 20 30 18 25 8 7 22 18 17 14 23 16 17 11 16 24 19 18 22 15 15 23 16 13 15 22 14 8 12 18 13 15 22 17 15 15 17 27 21 19 21 24 17 10 12 14 19 17 22 18 19 17 28 19 15 14 16 28 17 20 15 11 22 18 19 16 21 17 24 19 22 22 20 10 20 18 18 18 21 18 23 18 32 26 21 21 22 20 22 16 17 20 22 21 17 13 13 11 9 5 0 1 1 1 0.188000 4.300 4.300 10.20 3396610 5 0 0 0 0 0 0 0 0 0 0 0 1 2 3 0 2 5 5 4 3 3 5 1 2 3 6 9 3 3 3 8 7 2 9 5 7 5 11 8 9 7 6 9 6 4 5 8 6 10 9 14 10 15 6 7 13 15 10 13 7 15 10 10 11 14 14 6 7 17 13 19 3 13 9 6 13 13 14 10 11 12 16 17 13 10 15 15 19 19 11 11 15 11 13 9 13 20 8 18 14 18 23 23 23 15 19 20 14 11 7 18 16 15 22 28 20 24 22 25 17 20 39 24 26 25 25 33 25 25 25 33 15 29 18 29 18 12 18 23 17 24 28 22 16 20 33 23 18 23 26 23 15 24 16 16 16 16 17 15 15 16 14 11 9 23 17 13 13 18 12 19 20 30 20 20 15 21 19 16 18 20 23 19 15 10 11 15 19 13 22 22 18 19 16 19 23 16 10 25 23 20 21 20 31 19 19 18 15 22 18 14 13 21 18 19 22 19 16 17 21 14 20 26 18 26 22 19 26 19 20 22 15 13 24 23 15 21 21 21 27 18 22 19 24 17 22 16 18 23 10 12 3 5 3 3 0 0 0.190000 4.350 4.350 10.30 3502025 3 0 0 0 0 0 0 0 0 0 0 0 0 3 0 3 2 3 4 4 3 4 5 10 7 6 6 4 5 12 10 6 6 13 10 6 7 14 9 6 13 10 12 16 3 9 9 7 5 6 13 11 10 8 11 19 12 14 13 16 13 14 9 12 14 13 14 16 10 14 7 16 18 16 9 15 11 20 15 10 14 14 11 14 17 10 6 16 10 15 12 17 17 20 15 7 12 23 15 8 13 12 8 16 15 20 16 16 20 14 11 20 24 23 20 16 18 27 25 31 27 27 25 21 31 27 20 23 24 32 17 21 34 27 17 19 19 25 30 27 21 24 28 30 19 26 21 14 16 21 23 27 8 17 21 17 11 23 15 22 15 18 10 17 20 23 18 18 17 19 22 15 22 21 19 23 18 18 26 17 18 26 18 24 15 22 23 23 19 23 25 23 24 26 10 21 16 32 23 18 19 24 21 28 26 22 19 19 14 30 21 24 23 22 21 13 27 20 27 24 15 20 22 22 13 25 14 19 32 21 18 18 23 22 22 14 18 20 24 14 19 20 18 17 24 29 27 20 12 18 17 11 9 2 3 2 1 0 0.192000 4.400 4.400 10.40 3593938 3 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 2 3 4 7 8 1 5 6 8 3 7 5 4 9 8 8 7 7 9 7 9 9 15 5 7 8 15 14 9 9 13 8 8 15 10 7 10 9 10 14 7 8 18 16 17 11 14 15 13 8 15 8 15 18 16 16 22 12 8 16 13 10 13 13 10 21 11 10 16 16 13 13 17 16 20 23 13 22 16 14 15 22 19 22 15 22 24 16 16 16 19 12 15 16 17 20 18 19 26 17 23 18 32 20 28 36 22 25 30 29 31 36 24 24 21 29 24 32 29 30 23 34 19 33 34 25 20 31 27 24 16 14 21 20 13 24 17 28 13 24 16 26 15 26 21 11 15 20 13 20 18 25 23 18 24 26 22 16 22 14 13 16 20 24 25 19 29 20 15 20 16 25 26 21 22 17 24 22 21 17 23 23 15 19 30 23 17 21 19 18 21 26 14 29 24 20 33 19 15 20 23 28 19 23 25 15 19 17 31 23 18 29 26 25 14 24 25 18 19 19 24 35 31 23 23 14 15 19 11 20 19 24 17 16 9 10 12 3 2 2 0 1 0.194000 4.450 4.450 10.50 3712573 7 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 5 3 5 4 3 11 3 10 4 6 7 8 5 5 5 8 9 12 7 7 11 8 6 7 9 10 13 10 6 13 9 9 9 11 14 14 12 13 10 6 13 13 15 12 13 19 8 14 13 16 11 13 14 15 9 15 16 13 16 17 17 17 23 18 16 19 10 13 18 16 10 9 21 11 22 14 20 14 18 13 15 12 13 14 16 14 15 20 29 17 14 18 8 15 21 15 19 15 22 20 17 15 23 26 16 26 24 23 23 23 23 30 24 29 28 26 35 33 31 22 23 22 20 37 22 27 33 26 27 26 17 16 18 27 22 21 24 18 18 18 17 15 18 14 19 24 22 15 20 21 15 19 25 15 16 26 19 22 29 20 16 13 15 16 32 24 23 13 33 17 22 18 18 23 24 22 21 20 26 21 16 22 18 18 16 15 26 26 17 22 21 13 25 24 13 23 18 18 25 32 20 24 21 17 19 24 24 23 33 19 19 21 32 18 22 23 19 23 32 18 31 22 25 23 23 31 29 21 16 20 20 15 22 14 12 5 10 9 2 1 0 1 0.196000 4.500 4.500 10.60 3829518 3 0 0 0 0 0 0 0 0 0 0 1 2 2 1 6 2 6 5 9 3 5 6 8 6 3 8 10 7 11 9 4 8 9 5 11 10 13 9 16 13 10 9 5 12 9 15 10 13 9 12 18 14 19 9 13 14 12 13 21 17 17 18 16 13 12 16 14 18 10 15 15 16 11 15 22 17 19 17 11 12 26 12 17 19 18 21 20 27 17 18 19 21 14 19 16 12 16 21 20 18 8 17 17 13 13 18 15 19 15 19 20 28 21 29 27 27 34 24 26 31 25 24 16 17 23 23 30 28 18 28 32 28 37 18 26 18 16 33 21 31 21 20 22 19 20 25 18 18 20 11 17 20 22 23 14 14 17 18 20 25 20 19 20 22 19 16 33 25 21 21 24 18 16 22 29 22 16 27 26 28 21 20 22 17 25 23 20 23 18 16 19 26 22 21 22 23 15 20 19 17 23 19 20 15 22 18 22 26 23 23 31 17 29 18 13 15 19 18 24 22 28 22 17 23 24 26 21 23 25 24 29 26 18 41 24 29 22 27 23 28 16 30 24 18 23 19 17 18 21 17 14 8 2 5 2 0 0 0.198000 4.550 4.550 10.70 3950740 3 0 0 0 0 0 0 0 0 0 1 1 1 2 1 3 7 5 6 7 7 7 4 5 6 4 1 8 9 10 9 8 10 8 12 6 10 8 10 8 11 9 10 15 7 11 8 13 11 13 15 15 17 12 10 8 17 12 9 14 12 14 11 14 21 14 15 20 18 16 8 15 22 24 14 10 18 14 15 16 12 10 16 21 16 25 17 20 17 17 20 15 24 15 17 22 25 17 13 22 18 20 19 11 21 22 21 16 21 24 16 22 17 21 17 24 22 24 35 27 24 28 24 32 37 34 25 24 29 37 37 25 28 21 23 24 22 21 20 25 22 32 19 21 22 24 20 21 20 22 18 27 17 14 20 22 22 22 14 19 20 20 21 23 22 14 20 21 23 20 18 23 20 25 31 24 18 22 14 23 22 21 23 27 27 20 21 18 22 23 24 23 21 18 22 17 22 21 35 15 24 24 12 27 30 27 28 22 31 24 24 19 27 24 28 23 25 26 35 27 22 29 21 24 18 19 26 33 29 31 23 25 19 24 26 21 10 23 24 26 28 20 27 26 17 29 22 18 14 22 8 10 11 4 4 1 2 0 0.200000 4.600 4.600 10.80 4068161 5 0 0 0 0 0 0 0 0 0 0 1 1 0 1 5 5 2 9 3 11 6 9 8 7 7 8 3 3 13 10 8 7 5 8 13 8 7 14 12 10 7 15 13 13 11 12 12 14 12 13 12 10 15 11 14 7 16 15 8 15 13 15 13 18 13 17 21 15 12 13 13 17 18 18 18 16 19 20 17 14 17 24 13 12 18 19 19 13 21 18 26 21 23 16 14 18 19 13 33 13 19 20 14 20 23 14 26 19 22 21 21 16 27 30 25 28 22 32 21 30 27 31 21 30 22 27 27 31 27 21 17 38 41 17 21 20 19 30 24 27 20 20 21 30 20 19 19 31 25 24 13 21 23 19 24 33 24 17 20 17 12 25 23 18 24 11 24 25 22 33 20 11 22 31 21 20 26 27 21 26 24 14 23 23 20 20 26 28 10 20 27 24 22 17 27 28 20 23 23 33 20 24 26 32 33 29 21 25 24 17 18 19 27 26 20 24 26 24 24 26 21 19 24 21 36 32 18 33 33 20 23 25 33 19 27 25 27 24 27 21 21 23 28 18 27 25 19 24 15 17 12 15 7 2 1 0 0 ", "%f ", Inf); %! assert (rows (x) == n); +## Test input validation +%!error sscanf () +%!error sscanf (1, "2") +%!error