Mercurial > octave
comparison libinterp/octave-value/ov.cc @ 31607:aac27ad79be6 stable
maint: Re-indent code after switch to using namespace macros.
* build-env.h, build-env.in.cc, Cell.h, __betainc__.cc, __eigs__.cc,
__ftp__.cc, __ichol__.cc, __ilu__.cc, __isprimelarge__.cc, __magick_read__.cc,
__pchip_deriv__.cc, amd.cc, base-text-renderer.cc, base-text-renderer.h,
besselj.cc, bitfcns.cc, bsxfun.cc, c-file-ptr-stream.h, call-stack.cc,
call-stack.h, ccolamd.cc, cellfun.cc, chol.cc, colamd.cc, dasrt.cc, data.cc,
debug.cc, defaults.cc, defaults.h, det.cc, display.cc, display.h, dlmread.cc,
dynamic-ld.cc, dynamic-ld.h, ellipj.cc, environment.cc, environment.h,
error.cc, error.h, errwarn.h, event-manager.cc, event-manager.h,
event-queue.cc, event-queue.h, fcn-info.cc, fcn-info.h, fft.cc, fft2.cc,
file-io.cc, filter.cc, find.cc, ft-text-renderer.cc, ft-text-renderer.h,
gcd.cc, gl-render.cc, gl-render.h, gl2ps-print.cc, gl2ps-print.h,
graphics-toolkit.cc, graphics-toolkit.h, graphics.cc, gsvd.cc, gtk-manager.cc,
gtk-manager.h, help.cc, help.h, hook-fcn.cc, hook-fcn.h, input.cc, input.h,
interpreter-private.cc, interpreter-private.h, interpreter.cc, interpreter.h,
inv.cc, jsondecode.cc, jsonencode.cc, latex-text-renderer.cc,
latex-text-renderer.h, load-path.cc, load-path.h, load-save.cc, load-save.h,
lookup.cc, ls-hdf5.cc, ls-mat4.cc, ls-mat5.cc, lsode.cc, lu.cc, mappers.cc,
matrix_type.cc, max.cc, mex.cc, mexproto.h, mxarray.h, mxtypes.in.h,
oct-errno.in.cc, oct-hdf5-types.cc, oct-hist.cc, oct-hist.h, oct-map.cc,
oct-map.h, oct-opengl.h, oct-prcstrm.h, oct-process.cc, oct-process.h,
oct-stdstrm.h, oct-stream.cc, oct-stream.h, oct-strstrm.h,
octave-default-image.h, ordqz.cc, ordschur.cc, pager.cc, pager.h, pinv.cc,
pow2.cc, pr-output.cc, psi.cc, qr.cc, quadcc.cc, rand.cc, regexp.cc,
settings.cc, settings.h, sighandlers.cc, sighandlers.h, sparse-xpow.cc,
sqrtm.cc, stack-frame.cc, stack-frame.h, stream-euler.cc, strfns.cc, svd.cc,
syminfo.cc, syminfo.h, symrcm.cc, symrec.cc, symrec.h, symscope.cc, symscope.h,
symtab.cc, symtab.h, sysdep.cc, sysdep.h, text-engine.cc, text-engine.h,
text-renderer.cc, text-renderer.h, time.cc, toplev.cc, typecast.cc,
url-handle-manager.cc, url-handle-manager.h, urlwrite.cc, utils.cc, utils.h,
variables.cc, variables.h, xdiv.cc, __delaunayn__.cc, __init_fltk__.cc,
__init_gnuplot__.cc, __ode15__.cc, __voronoi__.cc, audioread.cc, convhulln.cc,
gzip.cc, cdef-class.cc, cdef-class.h, cdef-fwd.h, cdef-manager.cc,
cdef-manager.h, cdef-method.cc, cdef-method.h, cdef-object.cc, cdef-object.h,
cdef-package.cc, cdef-package.h, cdef-property.cc, cdef-property.h,
cdef-utils.cc, cdef-utils.h, ov-base-diag.cc, ov-base-int.cc, ov-base-mat.cc,
ov-base-mat.h, ov-base-scalar.cc, ov-base.cc, ov-base.h, ov-bool-mat.cc,
ov-bool-mat.h, ov-bool-sparse.cc, ov-bool.cc, ov-builtin.h, ov-cell.cc,
ov-ch-mat.cc, ov-class.cc, ov-class.h, ov-classdef.cc, ov-classdef.h,
ov-complex.cc, ov-cx-diag.cc, ov-cx-mat.cc, ov-cx-sparse.cc, ov-dld-fcn.cc,
ov-dld-fcn.h, ov-fcn-handle.cc, ov-fcn-handle.h, ov-fcn.h, ov-float.cc,
ov-flt-complex.cc, ov-flt-cx-diag.cc, ov-flt-cx-mat.cc, ov-flt-re-diag.cc,
ov-flt-re-mat.cc, ov-flt-re-mat.h, ov-intx.h, ov-java.cc, ov-lazy-idx.cc,
ov-legacy-range.cc, ov-magic-int.cc, ov-mex-fcn.cc, ov-mex-fcn.h,
ov-null-mat.cc, ov-perm.cc, ov-range.cc, ov-re-diag.cc, ov-re-mat.cc,
ov-re-mat.h, ov-re-sparse.cc, ov-scalar.cc, ov-str-mat.cc, ov-struct.cc,
ov-typeinfo.cc, ov-typeinfo.h, ov-usr-fcn.cc, ov-usr-fcn.h, ov.cc, ov.h, ovl.h,
octave.cc, octave.h, op-b-sbm.cc, op-bm-sbm.cc, op-cs-scm.cc, op-fm-fcm.cc,
op-fs-fcm.cc, op-s-scm.cc, op-scm-cs.cc, op-scm-s.cc, op-sm-cs.cc, ops.h,
anon-fcn-validator.cc, anon-fcn-validator.h, bp-table.cc, bp-table.h,
comment-list.cc, comment-list.h, filepos.h, lex.h, oct-lvalue.cc, oct-lvalue.h,
parse.h, profiler.cc, profiler.h, pt-anon-scopes.cc, pt-anon-scopes.h,
pt-arg-list.cc, pt-arg-list.h, pt-args-block.cc, pt-args-block.h,
pt-array-list.cc, pt-array-list.h, pt-assign.cc, pt-assign.h, pt-binop.cc,
pt-binop.h, pt-bp.cc, pt-bp.h, pt-cbinop.cc, pt-cbinop.h, pt-cell.cc,
pt-cell.h, pt-check.cc, pt-check.h, pt-classdef.cc, pt-classdef.h, pt-cmd.h,
pt-colon.cc, pt-colon.h, pt-const.cc, pt-const.h, pt-decl.cc, pt-decl.h,
pt-eval.cc, pt-eval.h, pt-except.cc, pt-except.h, pt-exp.cc, pt-exp.h,
pt-fcn-handle.cc, pt-fcn-handle.h, pt-id.cc, pt-id.h, pt-idx.cc, pt-idx.h,
pt-jump.h, pt-loop.cc, pt-loop.h, pt-mat.cc, pt-mat.h, pt-misc.cc, pt-misc.h,
pt-pr-code.cc, pt-pr-code.h, pt-select.cc, pt-select.h, pt-spmd.cc, pt-spmd.h,
pt-stmt.cc, pt-stmt.h, pt-tm-const.cc, pt-tm-const.h, pt-unop.cc, pt-unop.h,
pt-walk.cc, pt-walk.h, pt.cc, pt.h, token.cc, token.h, Range.cc, Range.h,
idx-vector.cc, idx-vector.h, range-fwd.h, CollocWt.cc, CollocWt.h,
aepbalance.cc, aepbalance.h, chol.cc, chol.h, gepbalance.cc, gepbalance.h,
gsvd.cc, gsvd.h, hess.cc, hess.h, lo-mappers.cc, lo-mappers.h, lo-specfun.cc,
lo-specfun.h, lu.cc, lu.h, oct-convn.cc, oct-convn.h, oct-fftw.cc, oct-fftw.h,
oct-norm.cc, oct-norm.h, oct-rand.cc, oct-rand.h, oct-spparms.cc,
oct-spparms.h, qr.cc, qr.h, qrp.cc, qrp.h, randgamma.cc, randgamma.h,
randmtzig.cc, randmtzig.h, randpoisson.cc, randpoisson.h, schur.cc, schur.h,
sparse-chol.cc, sparse-chol.h, sparse-lu.cc, sparse-lu.h, sparse-qr.cc,
sparse-qr.h, svd.cc, svd.h, child-list.cc, child-list.h, dir-ops.cc, dir-ops.h,
file-ops.cc, file-ops.h, file-stat.cc, file-stat.h, lo-sysdep.cc, lo-sysdep.h,
lo-sysinfo.cc, lo-sysinfo.h, mach-info.cc, mach-info.h, oct-env.cc, oct-env.h,
oct-group.cc, oct-group.h, oct-password.cc, oct-password.h, oct-syscalls.cc,
oct-syscalls.h, oct-time.cc, oct-time.h, oct-uname.cc, oct-uname.h,
action-container.cc, action-container.h, base-list.h, cmd-edit.cc, cmd-edit.h,
cmd-hist.cc, cmd-hist.h, f77-fcn.h, file-info.cc, file-info.h,
lo-array-errwarn.cc, lo-array-errwarn.h, lo-hash.cc, lo-hash.h, lo-ieee.h,
lo-regexp.cc, lo-regexp.h, lo-utils.cc, lo-utils.h, oct-base64.cc,
oct-base64.h, oct-glob.cc, oct-glob.h, oct-inttypes.h, oct-mutex.cc,
oct-mutex.h, oct-refcount.h, oct-shlib.cc, oct-shlib.h, oct-sparse.cc,
oct-sparse.h, oct-string.h, octave-preserve-stream-state.h, pathsearch.cc,
pathsearch.h, quit.cc, quit.h, unwind-prot.cc, unwind-prot.h, url-transfer.cc,
url-transfer.h:
Re-indent code after switch to using namespace macros.
author | Rik <rik@octave.org> |
---|---|
date | Thu, 01 Dec 2022 18:02:15 -0800 |
parents | e88a07dec498 |
children | 23664317f0d3 597f3ee61a48 |
comparison
equal
deleted
inserted
replaced
31605:e88a07dec498 | 31607:aac27ad79be6 |
---|---|
1081 # pragma GCC diagnostic push | 1081 # pragma GCC diagnostic push |
1082 # pragma GCC diagnostic ignored "-Wdeprecated-declarations" | 1082 # pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
1083 #endif | 1083 #endif |
1084 | 1084 |
1085 return dynamic_cast<octave_base_value *> | 1085 return dynamic_cast<octave_base_value *> |
1086 (new octave_legacy_range (Range (base, inc, limit))); | 1086 (new octave_legacy_range (Range (base, inc, limit))); |
1087 | 1087 |
1088 #if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC) | 1088 #if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC) |
1089 # pragma GCC diagnostic pop | 1089 # pragma GCC diagnostic pop |
1090 #endif | 1090 #endif |
1091 } | 1091 } |
1199 bool /*force_range*/) | 1199 bool /*force_range*/) |
1200 #if 0 | 1200 #if 0 |
1201 : m_rep (force_range || optimize_range | 1201 : m_rep (force_range || optimize_range |
1202 ? dynamic_cast<octave_base_value *> (new octave_char_range (r, type)) | 1202 ? dynamic_cast<octave_base_value *> (new octave_char_range (r, type)) |
1203 : dynamic_cast<octave_base_value *> (type == '"' | 1203 : dynamic_cast<octave_base_value *> (type == '"' |
1204 ? new octave_char_matrix_dq_str (r.array_value ()) | 1204 ? new octave_char_matrix_dq_str (r.array_value ()) |
1205 : new octave_char_matrix_sq_str (r.array_value ()))) | 1205 : new octave_char_matrix_sq_str (r.array_value ()))) |
1206 #else | 1206 #else |
1207 : m_rep (type == '"' | 1207 : m_rep (type == '"' |
1208 ? new octave_char_matrix_dq_str (r.array_value ()) | 1208 ? new octave_char_matrix_dq_str (r.array_value ()) |
1209 : new octave_char_matrix_sq_str (r.array_value ())) | 1209 : new octave_char_matrix_sq_str (r.array_value ())) |
1210 #endif | 1210 #endif |
1889 frc_vec_conv)); | 1889 frc_vec_conv)); |
1890 } | 1890 } |
1891 | 1891 |
1892 ComplexColumnVector | 1892 ComplexColumnVector |
1893 octave_value::complex_column_vector_value (bool force_string_conv, | 1893 octave_value::complex_column_vector_value (bool force_string_conv, |
1894 bool frc_vec_conv) const | 1894 bool frc_vec_conv) const |
1895 { | 1895 { |
1896 return ComplexColumnVector (complex_vector_value (force_string_conv, | 1896 return ComplexColumnVector (complex_vector_value (force_string_conv, |
1897 frc_vec_conv)); | 1897 frc_vec_conv)); |
1898 } | 1898 } |
1899 | 1899 |
1900 RowVector | 1900 RowVector |
1901 octave_value::row_vector_value (bool force_string_conv, | 1901 octave_value::row_vector_value (bool force_string_conv, |
1902 bool frc_vec_conv) const | 1902 bool frc_vec_conv) const |
1908 ComplexRowVector | 1908 ComplexRowVector |
1909 octave_value::complex_row_vector_value (bool force_string_conv, | 1909 octave_value::complex_row_vector_value (bool force_string_conv, |
1910 bool frc_vec_conv) const | 1910 bool frc_vec_conv) const |
1911 { | 1911 { |
1912 return ComplexRowVector (complex_vector_value (force_string_conv, | 1912 return ComplexRowVector (complex_vector_value (force_string_conv, |
1913 frc_vec_conv)); | 1913 frc_vec_conv)); |
1914 } | 1914 } |
1915 | 1915 |
1916 Array<double> | 1916 Array<double> |
1917 octave_value::vector_value (bool force_string_conv, | 1917 octave_value::vector_value (bool force_string_conv, |
1918 bool force_vector_conversion) const | 1918 bool force_vector_conversion) const |
1919 { | 1919 { |
1920 Array<double> retval = array_value (force_string_conv); | 1920 Array<double> retval = array_value (force_string_conv); |
1921 | 1921 |
1922 return retval.reshape (make_vector_dims (retval.dims (), | 1922 return retval.reshape (make_vector_dims (retval.dims (), |
1923 force_vector_conversion, | 1923 force_vector_conversion, |
1924 type_name (), "real vector")); | 1924 type_name (), "real vector")); |
1925 } | 1925 } |
1926 | 1926 |
1927 template <typename T> | 1927 template <typename T> |
1928 static Array<int> | 1928 static Array<int> |
1929 convert_to_int_array (const Array<octave_int<T>>& A) | 1929 convert_to_int_array (const Array<octave_int<T>>& A) |
1987 else | 1987 else |
1988 retval = Array<int> (a); | 1988 retval = Array<int> (a); |
1989 } | 1989 } |
1990 | 1990 |
1991 return retval.reshape (make_vector_dims (retval.dims (), | 1991 return retval.reshape (make_vector_dims (retval.dims (), |
1992 force_vector_conversion, | 1992 force_vector_conversion, |
1993 type_name (), "integer vector")); | 1993 type_name (), "integer vector")); |
1994 } | 1994 } |
1995 | 1995 |
1996 template <typename T> | 1996 template <typename T> |
1997 static Array<octave_idx_type> | 1997 static Array<octave_idx_type> |
1998 convert_to_octave_idx_type_array (const Array<octave_int<T>>& A) | 1998 convert_to_octave_idx_type_array (const Array<octave_int<T>>& A) |
2006 return retval; | 2006 return retval; |
2007 } | 2007 } |
2008 | 2008 |
2009 Array<octave_idx_type> | 2009 Array<octave_idx_type> |
2010 octave_value::octave_idx_type_vector_value (bool require_int, | 2010 octave_value::octave_idx_type_vector_value (bool require_int, |
2011 bool force_string_conv, | 2011 bool force_string_conv, |
2012 bool force_vector_conversion) const | 2012 bool force_vector_conversion) const |
2013 { | 2013 { |
2014 Array<octave_idx_type> retval; | 2014 Array<octave_idx_type> retval; |
2015 | 2015 |
2016 if (isinteger ()) | 2016 if (isinteger ()) |
2017 { | 2017 { |
2057 else | 2057 else |
2058 retval = Array<octave_idx_type> (a); | 2058 retval = Array<octave_idx_type> (a); |
2059 } | 2059 } |
2060 | 2060 |
2061 return retval.reshape (make_vector_dims (retval.dims (), | 2061 return retval.reshape (make_vector_dims (retval.dims (), |
2062 force_vector_conversion, | 2062 force_vector_conversion, |
2063 type_name (), "integer vector")); | 2063 type_name (), "integer vector")); |
2064 } | 2064 } |
2065 | 2065 |
2066 Array<Complex> | 2066 Array<Complex> |
2067 octave_value::complex_vector_value (bool force_string_conv, | 2067 octave_value::complex_vector_value (bool force_string_conv, |
2068 bool force_vector_conversion) const | 2068 bool force_vector_conversion) const |
2069 { | 2069 { |
2070 Array<Complex> retval = complex_array_value (force_string_conv); | 2070 Array<Complex> retval = complex_array_value (force_string_conv); |
2071 | 2071 |
2072 return retval.reshape (make_vector_dims (retval.dims (), | 2072 return retval.reshape (make_vector_dims (retval.dims (), |
2073 force_vector_conversion, | 2073 force_vector_conversion, |
2074 type_name (), "complex vector")); | 2074 type_name (), "complex vector")); |
2075 } | 2075 } |
2076 | 2076 |
2077 FloatColumnVector | 2077 FloatColumnVector |
2078 octave_value::float_column_vector_value (bool force_string_conv, | 2078 octave_value::float_column_vector_value (bool force_string_conv, |
2079 bool frc_vec_conv) const | 2079 bool frc_vec_conv) const |
2080 { | 2080 { |
2081 return FloatColumnVector (float_vector_value (force_string_conv, | 2081 return FloatColumnVector (float_vector_value (force_string_conv, |
2082 frc_vec_conv)); | 2082 frc_vec_conv)); |
2083 } | 2083 } |
2084 | 2084 |
2085 FloatComplexColumnVector | 2085 FloatComplexColumnVector |
2086 octave_value::float_complex_column_vector_value (bool force_string_conv, | 2086 octave_value::float_complex_column_vector_value (bool force_string_conv, |
2087 bool frc_vec_conv) const | 2087 bool frc_vec_conv) const |
2088 { | 2088 { |
2089 return | 2089 return |
2090 FloatComplexColumnVector (float_complex_vector_value (force_string_conv, | 2090 FloatComplexColumnVector (float_complex_vector_value (force_string_conv, |
2091 frc_vec_conv)); | 2091 frc_vec_conv)); |
2092 } | 2092 } |
2093 | 2093 |
2094 FloatRowVector | 2094 FloatRowVector |
2095 octave_value::float_row_vector_value (bool force_string_conv, | 2095 octave_value::float_row_vector_value (bool force_string_conv, |
2096 bool frc_vec_conv) const | 2096 bool frc_vec_conv) const |
2097 { | 2097 { |
2098 return FloatRowVector (float_vector_value (force_string_conv, | 2098 return FloatRowVector (float_vector_value (force_string_conv, |
2099 frc_vec_conv)); | 2099 frc_vec_conv)); |
2100 } | 2100 } |
2101 | 2101 |
2102 FloatComplexRowVector | 2102 FloatComplexRowVector |
2103 octave_value::float_complex_row_vector_value (bool force_string_conv, | 2103 octave_value::float_complex_row_vector_value (bool force_string_conv, |
2104 bool frc_vec_conv) const | 2104 bool frc_vec_conv) const |
2105 { | 2105 { |
2106 return FloatComplexRowVector (float_complex_vector_value (force_string_conv, | 2106 return FloatComplexRowVector (float_complex_vector_value (force_string_conv, |
2107 frc_vec_conv)); | 2107 frc_vec_conv)); |
2108 } | 2108 } |
2109 | 2109 |
2110 Array<float> | 2110 Array<float> |
2111 octave_value::float_vector_value (bool force_string_conv, | 2111 octave_value::float_vector_value (bool force_string_conv, |
2112 bool force_vector_conversion) const | 2112 bool force_vector_conversion) const |
2113 { | 2113 { |
2114 Array<float> retval = float_array_value (force_string_conv); | 2114 Array<float> retval = float_array_value (force_string_conv); |
2115 | 2115 |
2116 return retval.reshape (make_vector_dims (retval.dims (), | 2116 return retval.reshape (make_vector_dims (retval.dims (), |
2117 force_vector_conversion, | 2117 force_vector_conversion, |
2118 type_name (), "real vector")); | 2118 type_name (), "real vector")); |
2119 } | 2119 } |
2120 | 2120 |
2121 Array<FloatComplex> | 2121 Array<FloatComplex> |
2122 octave_value::float_complex_vector_value (bool force_string_conv, | 2122 octave_value::float_complex_vector_value (bool force_string_conv, |
2123 bool force_vector_conversion) const | 2123 bool force_vector_conversion) const |
2124 { | 2124 { |
2125 Array<FloatComplex> retval = float_complex_array_value (force_string_conv); | 2125 Array<FloatComplex> retval = float_complex_array_value (force_string_conv); |
2126 | 2126 |
2127 return retval.reshape (make_vector_dims (retval.dims (), | 2127 return retval.reshape (make_vector_dims (retval.dims (), |
2128 force_vector_conversion, | 2128 force_vector_conversion, |
2129 type_name (), "complex vector")); | 2129 type_name (), "complex vector")); |
2130 } | 2130 } |
2131 | 2131 |
2132 // NAME can't always be "x ## FCN" because some of the original | 2132 // NAME can't always be "x ## FCN" because some of the original |
2133 // value extraction functions perform implicit type conversions that we | 2133 // value extraction functions perform implicit type conversions that we |
2134 // wish to avoid for these functions. | 2134 // wish to avoid for these functions. |
2212 XVALUE_EXTRACTOR (SparseBoolMatrix, xsparse_bool_matrix_value, sparse_bool_matrix_value) | 2212 XVALUE_EXTRACTOR (SparseBoolMatrix, xsparse_bool_matrix_value, sparse_bool_matrix_value) |
2213 | 2213 |
2214 XVALUE_EXTRACTOR (DiagMatrix, xdiag_matrix_value, diag_matrix_value) | 2214 XVALUE_EXTRACTOR (DiagMatrix, xdiag_matrix_value, diag_matrix_value) |
2215 XVALUE_EXTRACTOR (FloatDiagMatrix, xfloat_diag_matrix_value, float_diag_matrix_value) | 2215 XVALUE_EXTRACTOR (FloatDiagMatrix, xfloat_diag_matrix_value, float_diag_matrix_value) |
2216 XVALUE_EXTRACTOR (ComplexDiagMatrix, xcomplex_diag_matrix_value, complex_diag_matrix_value) | 2216 XVALUE_EXTRACTOR (ComplexDiagMatrix, xcomplex_diag_matrix_value, complex_diag_matrix_value) |
2217 XVALUE_EXTRACTOR (FloatComplexDiagMatrix, xfloat_complex_diag_matrix_value, float_complex_diag_matrix_value) | 2217 XVALUE_EXTRACTOR (FloatComplexDiagMatrix, xfloat_complex_diag_matrix_value, |
2218 float_complex_diag_matrix_value) | |
2218 | 2219 |
2219 XVALUE_EXTRACTOR (PermMatrix, xperm_matrix_value, perm_matrix_value) | 2220 XVALUE_EXTRACTOR (PermMatrix, xperm_matrix_value, perm_matrix_value) |
2220 | 2221 |
2221 XVALUE_EXTRACTOR (octave_int8, xint8_scalar_value, int8_scalar_value) | 2222 XVALUE_EXTRACTOR (octave_int8, xint8_scalar_value, int8_scalar_value) |
2222 XVALUE_EXTRACTOR (octave_int16, xint16_scalar_value, int16_scalar_value) | 2223 XVALUE_EXTRACTOR (octave_int16, xint16_scalar_value, int16_scalar_value) |
2270 | 2271 |
2271 XVALUE_EXTRACTOR (RowVector, xrow_vector_value, row_vector_value) | 2272 XVALUE_EXTRACTOR (RowVector, xrow_vector_value, row_vector_value) |
2272 XVALUE_EXTRACTOR (ComplexRowVector, xcomplex_row_vector_value, complex_row_vector_value) | 2273 XVALUE_EXTRACTOR (ComplexRowVector, xcomplex_row_vector_value, complex_row_vector_value) |
2273 | 2274 |
2274 XVALUE_EXTRACTOR (FloatColumnVector, xfloat_column_vector_value, float_column_vector_value) | 2275 XVALUE_EXTRACTOR (FloatColumnVector, xfloat_column_vector_value, float_column_vector_value) |
2275 XVALUE_EXTRACTOR (FloatComplexColumnVector, xfloat_complex_column_vector_value, float_complex_column_vector_value) | 2276 XVALUE_EXTRACTOR (FloatComplexColumnVector, xfloat_complex_column_vector_value, |
2277 float_complex_column_vector_value) | |
2276 | 2278 |
2277 XVALUE_EXTRACTOR (FloatRowVector, xfloat_row_vector_value, float_row_vector_value) | 2279 XVALUE_EXTRACTOR (FloatRowVector, xfloat_row_vector_value, float_row_vector_value) |
2278 XVALUE_EXTRACTOR (FloatComplexRowVector, xfloat_complex_row_vector_value, float_complex_row_vector_value) | 2280 XVALUE_EXTRACTOR (FloatComplexRowVector, xfloat_complex_row_vector_value, |
2281 float_complex_row_vector_value) | |
2279 | 2282 |
2280 XVALUE_EXTRACTOR (Array<int>, xint_vector_value, int_vector_value) | 2283 XVALUE_EXTRACTOR (Array<int>, xint_vector_value, int_vector_value) |
2281 XVALUE_EXTRACTOR (Array<octave_idx_type>, xoctave_idx_type_vector_value, octave_idx_type_vector_value) | 2284 XVALUE_EXTRACTOR (Array<octave_idx_type>, xoctave_idx_type_vector_value, |
2285 octave_idx_type_vector_value) | |
2282 | 2286 |
2283 XVALUE_EXTRACTOR (Array<double>, xvector_value, vector_value) | 2287 XVALUE_EXTRACTOR (Array<double>, xvector_value, vector_value) |
2284 XVALUE_EXTRACTOR (Array<Complex>, xcomplex_vector_value, complex_vector_value) | 2288 XVALUE_EXTRACTOR (Array<Complex>, xcomplex_vector_value, complex_vector_value) |
2285 | 2289 |
2286 XVALUE_EXTRACTOR (Array<float>, xfloat_vector_value, float_vector_value) | 2290 XVALUE_EXTRACTOR (Array<float>, xfloat_vector_value, float_vector_value) |
2514 | 2518 |
2515 octave_base_value *tmp = cf (*m_rep); | 2519 octave_base_value *tmp = cf (*m_rep); |
2516 | 2520 |
2517 if (! tmp) | 2521 if (! tmp) |
2518 err_unary_op_conversion_failed | 2522 err_unary_op_conversion_failed |
2519 (octave_value::unary_op_as_string (op), type_name ()); | 2523 (octave_value::unary_op_as_string (op), type_name ()); |
2520 | 2524 |
2521 octave_base_value *old_rep = m_rep; | 2525 octave_base_value *old_rep = m_rep; |
2522 m_rep = tmp; | 2526 m_rep = tmp; |
2523 | 2527 |
2524 t = type_id (); | 2528 t = type_id (); |
2686 return octave_value (rhs.empty_clone ()); | 2690 return octave_value (rhs.empty_clone ()); |
2687 } | 2691 } |
2688 | 2692 |
2689 OCTAVE_BEGIN_NAMESPACE(octave) | 2693 OCTAVE_BEGIN_NAMESPACE(octave) |
2690 | 2694 |
2691 OCTAVE_NORETURN static void | 2695 OCTAVE_NORETURN static void |
2692 err_binary_op (const std::string& on, const std::string& tn1, | 2696 err_binary_op (const std::string& on, const std::string& tn1, |
2693 const std::string& tn2) | 2697 const std::string& tn2) |
2694 { | 2698 { |
2695 error ("binary operator '%s' not implemented for '%s' by '%s' operations", | 2699 error ("binary operator '%s' not implemented for '%s' by '%s' operations", |
2696 on.c_str (), tn1.c_str (), tn2.c_str ()); | 2700 on.c_str (), tn1.c_str (), tn2.c_str ()); |
2697 } | 2701 } |
2698 | 2702 |
2699 OCTAVE_NORETURN static void | 2703 OCTAVE_NORETURN static void |
2700 err_binary_op_conv (const std::string& on) | 2704 err_binary_op_conv (const std::string& on) |
2701 { | 2705 { |
2702 error ("type conversion failed for binary operator '%s'", on.c_str ()); | 2706 error ("type conversion failed for binary operator '%s'", on.c_str ()); |
2703 } | 2707 } |
2704 | 2708 |
2705 octave_value | 2709 octave_value |
2706 binary_op (type_info& ti, octave_value::binary_op op, | 2710 binary_op (type_info& ti, octave_value::binary_op op, |
2707 const octave_value& v1, const octave_value& v2) | 2711 const octave_value& v1, const octave_value& v2) |
2708 { | 2712 { |
2709 octave_value retval; | 2713 octave_value retval; |
2710 | 2714 |
2711 int t1 = v1.type_id (); | 2715 int t1 = v1.type_id (); |
2712 int t2 = v2.type_id (); | 2716 int t2 = v2.type_id (); |
2713 | 2717 |
2714 if (t1 == octave_class::static_type_id () | 2718 if (t1 == octave_class::static_type_id () |
2715 || t2 == octave_class::static_type_id () | 2719 || t2 == octave_class::static_type_id () |
2716 || t1 == octave_classdef::static_type_id () | 2720 || t1 == octave_classdef::static_type_id () |
2717 || t2 == octave_classdef::static_type_id ()) | 2721 || t2 == octave_classdef::static_type_id ()) |
2718 { | 2722 { |
2719 type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op); | 2723 type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op); |
2720 | 2724 |
2721 if (! f) | 2725 if (! f) |
2722 err_binary_op (octave_value::binary_op_as_string (op), | 2726 err_binary_op (octave_value::binary_op_as_string (op), |
2723 v1.class_name (), v2.class_name ()); | 2727 v1.class_name (), v2.class_name ()); |
2724 | 2728 |
2729 retval = f (v1, v2); | |
2730 } | |
2731 else | |
2732 { | |
2733 // FIXME: we need to handle overloading operators for built-in | |
2734 // classes (double, char, int8, etc.) | |
2735 | |
2736 type_info::binary_op_fcn f | |
2737 = ti.lookup_binary_op (op, t1, t2); | |
2738 | |
2739 if (f) | |
2740 retval = f (v1.get_rep (), v2.get_rep ()); | |
2741 else | |
2742 { | |
2743 octave_value tv1; | |
2744 octave_base_value::type_conv_info cf1 | |
2745 = v1.numeric_conversion_function (); | |
2746 | |
2747 octave_value tv2; | |
2748 octave_base_value::type_conv_info cf2 | |
2749 = v2.numeric_conversion_function (); | |
2750 | |
2751 // Try biased (one-sided) conversions first. | |
2752 if (cf2.type_id () >= 0 | |
2753 && ti.lookup_binary_op (op, t1, cf2.type_id ())) | |
2754 cf1 = nullptr; | |
2755 else if (cf1.type_id () >= 0 | |
2756 && ti.lookup_binary_op (op, cf1.type_id (), t2)) | |
2757 cf2 = nullptr; | |
2758 | |
2759 if (cf1) | |
2760 { | |
2761 octave_base_value *tmp = cf1 (v1.get_rep ()); | |
2762 | |
2763 if (! tmp) | |
2764 err_binary_op_conv (octave_value::binary_op_as_string (op)); | |
2765 | |
2766 tv1 = octave_value (tmp); | |
2767 t1 = tv1.type_id (); | |
2768 } | |
2769 else | |
2770 tv1 = v1; | |
2771 | |
2772 if (cf2) | |
2773 { | |
2774 octave_base_value *tmp = cf2 (v2.get_rep ()); | |
2775 | |
2776 if (! tmp) | |
2777 err_binary_op_conv (octave_value::binary_op_as_string (op)); | |
2778 | |
2779 tv2 = octave_value (tmp); | |
2780 t2 = tv2.type_id (); | |
2781 } | |
2782 else | |
2783 tv2 = v2; | |
2784 | |
2785 if (cf1 || cf2) | |
2786 { | |
2787 retval = binary_op (op, tv1, tv2); | |
2788 } | |
2789 else | |
2790 { | |
2791 //demote double -> single and try again | |
2792 cf1 = tv1.numeric_demotion_function (); | |
2793 | |
2794 cf2 = tv2.numeric_demotion_function (); | |
2795 | |
2796 // Try biased (one-sided) conversions first. | |
2797 if (cf2.type_id () >= 0 | |
2798 && ti.lookup_binary_op (op, t1, cf2.type_id ())) | |
2799 cf1 = nullptr; | |
2800 else if (cf1.type_id () >= 0 | |
2801 && ti.lookup_binary_op (op, cf1.type_id (), t2)) | |
2802 cf2 = nullptr; | |
2803 | |
2804 if (cf1) | |
2805 { | |
2806 octave_base_value *tmp = cf1 (tv1.get_rep ()); | |
2807 | |
2808 if (! tmp) | |
2809 err_binary_op_conv (octave_value::binary_op_as_string (op)); | |
2810 | |
2811 tv1 = octave_value (tmp); | |
2812 t1 = tv1.type_id (); | |
2813 } | |
2814 | |
2815 if (cf2) | |
2816 { | |
2817 octave_base_value *tmp = cf2 (tv2.get_rep ()); | |
2818 | |
2819 if (! tmp) | |
2820 err_binary_op_conv (octave_value::binary_op_as_string (op)); | |
2821 | |
2822 tv2 = octave_value (tmp); | |
2823 t2 = tv2.type_id (); | |
2824 } | |
2825 | |
2826 if (! cf1 && ! cf2) | |
2827 err_binary_op (octave_value::binary_op_as_string (op), | |
2828 v1.type_name (), v2.type_name ()); | |
2829 | |
2830 f = ti.lookup_binary_op (op, t1, t2); | |
2831 | |
2832 if (! f) | |
2833 err_binary_op (octave_value::binary_op_as_string (op), | |
2834 v1.type_name (), v2.type_name ()); | |
2835 | |
2836 retval = f (tv1.get_rep (), tv2.get_rep ()); | |
2837 } | |
2838 } | |
2839 } | |
2840 | |
2841 return retval; | |
2842 } | |
2843 | |
2844 octave_value | |
2845 binary_op (octave_value::binary_op op, const octave_value& v1, | |
2846 const octave_value& v2) | |
2847 { | |
2848 type_info& ti = __get_type_info__ (); | |
2849 | |
2850 return binary_op (ti, op, v1, v2); | |
2851 } | |
2852 | |
2853 static octave_value | |
2854 decompose_binary_op (type_info& ti, octave_value::compound_binary_op op, | |
2855 const octave_value& v1, const octave_value& v2) | |
2856 { | |
2857 switch (op) | |
2858 { | |
2859 case octave_value::op_trans_mul: | |
2860 return binary_op (octave_value::op_mul, | |
2861 unary_op (octave_value::op_transpose, v1), v2); | |
2862 | |
2863 case octave_value::op_mul_trans: | |
2864 return binary_op (ti, octave_value::op_mul, | |
2865 v1, unary_op (octave_value::op_transpose, v2)); | |
2866 | |
2867 case octave_value::op_herm_mul: | |
2868 return binary_op (ti, octave_value::op_mul, | |
2869 unary_op (octave_value::op_hermitian, v1), v2); | |
2870 | |
2871 case octave_value::op_mul_herm: | |
2872 return binary_op (ti, octave_value::op_mul, | |
2873 v1, unary_op (octave_value::op_hermitian, v2)); | |
2874 | |
2875 case octave_value::op_trans_ldiv: | |
2876 return binary_op (ti, octave_value::op_ldiv, | |
2877 unary_op (octave_value::op_transpose, v1), v2); | |
2878 | |
2879 case octave_value::op_herm_ldiv: | |
2880 return binary_op (ti, octave_value::op_ldiv, | |
2881 unary_op (octave_value::op_hermitian, v1), v2); | |
2882 | |
2883 case octave_value::op_el_not_and: | |
2884 return binary_op (ti, octave_value::op_el_and, | |
2885 unary_op (octave_value::op_not, v1), v2); | |
2886 | |
2887 case octave_value::op_el_not_or: | |
2888 return binary_op (ti, octave_value::op_el_or, | |
2889 unary_op (octave_value::op_not, v1), v2); | |
2890 | |
2891 case octave_value::op_el_and_not: | |
2892 return binary_op (ti, octave_value::op_el_and, | |
2893 v1, unary_op (octave_value::op_not, v2)); | |
2894 | |
2895 case octave_value::op_el_or_not: | |
2896 return binary_op (ti, octave_value::op_el_or, | |
2897 v1, unary_op (octave_value::op_not, v2)); | |
2898 | |
2899 default: | |
2900 error ("invalid compound operator"); | |
2901 } | |
2902 } | |
2903 | |
2904 octave_value | |
2905 binary_op (type_info& ti, octave_value::compound_binary_op op, | |
2906 const octave_value& v1, const octave_value& v2) | |
2907 { | |
2908 octave_value retval; | |
2909 | |
2910 int t1 = v1.type_id (); | |
2911 int t2 = v2.type_id (); | |
2912 | |
2913 if (t1 == octave_class::static_type_id () | |
2914 || t2 == octave_class::static_type_id () | |
2915 || t1 == octave_classdef::static_type_id () | |
2916 || t2 == octave_classdef::static_type_id ()) | |
2917 { | |
2918 type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op); | |
2919 | |
2920 if (f) | |
2725 retval = f (v1, v2); | 2921 retval = f (v1, v2); |
2726 } | 2922 else |
2727 else | 2923 retval = decompose_binary_op (ti, op, v1, v2); |
2728 { | 2924 } |
2729 // FIXME: we need to handle overloading operators for built-in | 2925 else |
2730 // classes (double, char, int8, etc.) | 2926 { |
2731 | 2927 type_info::binary_op_fcn f = ti.lookup_binary_op (op, t1, t2); |
2732 type_info::binary_op_fcn f | 2928 |
2733 = ti.lookup_binary_op (op, t1, t2); | 2929 if (f) |
2734 | 2930 retval = f (v1.get_rep (), v2.get_rep ()); |
2735 if (f) | 2931 else |
2736 retval = f (v1.get_rep (), v2.get_rep ()); | 2932 retval = decompose_binary_op (ti, op, v1, v2); |
2737 else | 2933 } |
2738 { | 2934 |
2739 octave_value tv1; | 2935 return retval; |
2740 octave_base_value::type_conv_info cf1 | 2936 } |
2741 = v1.numeric_conversion_function (); | 2937 |
2742 | 2938 octave_value |
2743 octave_value tv2; | 2939 binary_op (octave_value::compound_binary_op op, |
2744 octave_base_value::type_conv_info cf2 | 2940 const octave_value& v1, const octave_value& v2) |
2745 = v2.numeric_conversion_function (); | 2941 { |
2746 | 2942 type_info& ti = __get_type_info__ (); |
2747 // Try biased (one-sided) conversions first. | 2943 |
2748 if (cf2.type_id () >= 0 | 2944 return binary_op (ti, op, v1, v2); |
2749 && ti.lookup_binary_op (op, t1, cf2.type_id ())) | 2945 } |
2750 cf1 = nullptr; | 2946 |
2751 else if (cf1.type_id () >= 0 | 2947 OCTAVE_NORETURN static void |
2752 && ti.lookup_binary_op (op, cf1.type_id (), t2)) | 2948 err_cat_op (const std::string& tn1, const std::string& tn2) |
2753 cf2 = nullptr; | 2949 { |
2754 | 2950 error ("concatenation operator not implemented for '%s' by '%s' operations", |
2755 if (cf1) | 2951 tn1.c_str (), tn2.c_str ()); |
2756 { | 2952 } |
2757 octave_base_value *tmp = cf1 (v1.get_rep ()); | 2953 |
2758 | 2954 OCTAVE_NORETURN static void |
2759 if (! tmp) | 2955 err_cat_op_conv (void) |
2760 err_binary_op_conv (octave_value::binary_op_as_string (op)); | 2956 { |
2761 | 2957 error ("type conversion failed for concatenation operator"); |
2762 tv1 = octave_value (tmp); | 2958 } |
2763 t1 = tv1.type_id (); | 2959 |
2764 } | 2960 octave_value |
2765 else | 2961 cat_op (type_info& ti, const octave_value& v1, |
2766 tv1 = v1; | 2962 const octave_value& v2, const Array<octave_idx_type>& ra_idx) |
2767 | 2963 { |
2768 if (cf2) | 2964 octave_value retval; |
2769 { | 2965 |
2770 octave_base_value *tmp = cf2 (v2.get_rep ()); | 2966 // Can't rapid return for concatenation with an empty object here as |
2771 | 2967 // something like cat(1,[],single([]) must return the correct type. |
2772 if (! tmp) | 2968 |
2773 err_binary_op_conv (octave_value::binary_op_as_string (op)); | 2969 int t1 = v1.type_id (); |
2774 | 2970 int t2 = v2.type_id (); |
2775 tv2 = octave_value (tmp); | 2971 |
2776 t2 = tv2.type_id (); | 2972 type_info::cat_op_fcn f = ti.lookup_cat_op (t1, t2); |
2777 } | 2973 |
2778 else | 2974 if (f) |
2779 tv2 = v2; | 2975 retval = f (v1.get_rep (), v2.get_rep (), ra_idx); |
2780 | 2976 else |
2781 if (cf1 || cf2) | 2977 { |
2782 { | 2978 octave_value tv1; |
2783 retval = binary_op (op, tv1, tv2); | 2979 octave_base_value::type_conv_info cf1 = v1.numeric_conversion_function (); |
2784 } | 2980 |
2785 else | 2981 octave_value tv2; |
2786 { | 2982 octave_base_value::type_conv_info cf2 = v2.numeric_conversion_function (); |
2787 //demote double -> single and try again | 2983 |
2788 cf1 = tv1.numeric_demotion_function (); | 2984 // Try biased (one-sided) conversions first. |
2789 | 2985 if (cf2.type_id () >= 0 && ti.lookup_cat_op (t1, cf2.type_id ())) |
2790 cf2 = tv2.numeric_demotion_function (); | 2986 cf1 = nullptr; |
2791 | 2987 else if (cf1.type_id () >= 0 && ti.lookup_cat_op (cf1.type_id (), t2)) |
2792 // Try biased (one-sided) conversions first. | 2988 cf2 = nullptr; |
2793 if (cf2.type_id () >= 0 | 2989 |
2794 && ti.lookup_binary_op (op, t1, cf2.type_id ())) | 2990 if (cf1) |
2795 cf1 = nullptr; | 2991 { |
2796 else if (cf1.type_id () >= 0 | 2992 octave_base_value *tmp = cf1 (v1.get_rep ()); |
2797 && ti.lookup_binary_op (op, cf1.type_id (), t2)) | 2993 |
2798 cf2 = nullptr; | 2994 if (! tmp) |
2799 | 2995 err_cat_op_conv (); |
2800 if (cf1) | 2996 |
2801 { | 2997 tv1 = octave_value (tmp); |
2802 octave_base_value *tmp = cf1 (tv1.get_rep ()); | 2998 t1 = tv1.type_id (); |
2803 | 2999 } |
2804 if (! tmp) | 3000 else |
2805 err_binary_op_conv (octave_value::binary_op_as_string (op)); | 3001 tv1 = v1; |
2806 | 3002 |
2807 tv1 = octave_value (tmp); | 3003 if (cf2) |
2808 t1 = tv1.type_id (); | 3004 { |
2809 } | 3005 octave_base_value *tmp = cf2 (v2.get_rep ()); |
2810 | 3006 |
2811 if (cf2) | 3007 if (! tmp) |
2812 { | 3008 err_cat_op_conv (); |
2813 octave_base_value *tmp = cf2 (tv2.get_rep ()); | 3009 |
2814 | 3010 tv2 = octave_value (tmp); |
2815 if (! tmp) | 3011 t2 = tv2.type_id (); |
2816 err_binary_op_conv (octave_value::binary_op_as_string (op)); | 3012 } |
2817 | 3013 else |
2818 tv2 = octave_value (tmp); | 3014 tv2 = v2; |
2819 t2 = tv2.type_id (); | 3015 |
2820 } | 3016 if (! cf1 && ! cf2) |
2821 | 3017 err_cat_op (v1.type_name (), v2.type_name ()); |
2822 if (! cf1 && ! cf2) | 3018 |
2823 err_binary_op (octave_value::binary_op_as_string (op), | 3019 retval = cat_op (ti, tv1, tv2, ra_idx); |
2824 v1.type_name (), v2.type_name ()); | 3020 } |
2825 | 3021 |
2826 f = ti.lookup_binary_op (op, t1, t2); | 3022 return retval; |
2827 | 3023 } |
2828 if (! f) | 3024 |
2829 err_binary_op (octave_value::binary_op_as_string (op), | 3025 octave_value |
2830 v1.type_name (), v2.type_name ()); | 3026 cat_op (const octave_value& v1, const octave_value& v2, |
2831 | 3027 const Array<octave_idx_type>& ra_idx) |
2832 retval = f (tv1.get_rep (), tv2.get_rep ()); | 3028 { |
2833 } | 3029 type_info& ti = __get_type_info__ (); |
2834 } | 3030 |
2835 } | 3031 return cat_op (ti, v1, v2, ra_idx); |
2836 | 3032 } |
2837 return retval; | 3033 |
2838 } | 3034 // Unless the colon operator is used with a class or classdef object, |
2839 | 3035 // then all arguments must be the same type or mixed with double |
2840 octave_value | 3036 // values. |
2841 binary_op (octave_value::binary_op op, const octave_value& v1, | 3037 |
2842 const octave_value& v2) | 3038 static builtin_type_t |
2843 { | 3039 get_colon_op_type (builtin_type_t op1_type, builtin_type_t op2_type) |
2844 type_info& ti = __get_type_info__ (); | 3040 { |
2845 | 3041 if (op1_type == op2_type) |
2846 return binary_op (ti, op, v1, v2); | 3042 return op1_type; |
2847 } | 3043 |
2848 | 3044 if (op1_type == btyp_double) |
2849 static octave_value | 3045 return op2_type; |
2850 decompose_binary_op (type_info& ti, octave_value::compound_binary_op op, | 3046 |
2851 const octave_value& v1, const octave_value& v2) | 3047 if (op2_type == btyp_double) |
2852 { | 3048 return op1_type; |
2853 switch (op) | 3049 |
2854 { | 3050 return btyp_unknown; |
2855 case octave_value::op_trans_mul: | 3051 } |
2856 return binary_op (octave_value::op_mul, | 3052 |
2857 unary_op (octave_value::op_transpose, v1), v2); | 3053 static builtin_type_t |
2858 | 3054 get_colon_op_type (const octave_value& base, const octave_value& increment, |
2859 case octave_value::op_mul_trans: | |
2860 return binary_op (ti, octave_value::op_mul, | |
2861 v1, unary_op (octave_value::op_transpose, v2)); | |
2862 | |
2863 case octave_value::op_herm_mul: | |
2864 return binary_op (ti, octave_value::op_mul, | |
2865 unary_op (octave_value::op_hermitian, v1), v2); | |
2866 | |
2867 case octave_value::op_mul_herm: | |
2868 return binary_op (ti, octave_value::op_mul, | |
2869 v1, unary_op (octave_value::op_hermitian, v2)); | |
2870 | |
2871 case octave_value::op_trans_ldiv: | |
2872 return binary_op (ti, octave_value::op_ldiv, | |
2873 unary_op (octave_value::op_transpose, v1), v2); | |
2874 | |
2875 case octave_value::op_herm_ldiv: | |
2876 return binary_op (ti, octave_value::op_ldiv, | |
2877 unary_op (octave_value::op_hermitian, v1), v2); | |
2878 | |
2879 case octave_value::op_el_not_and: | |
2880 return binary_op (ti, octave_value::op_el_and, | |
2881 unary_op (octave_value::op_not, v1), v2); | |
2882 | |
2883 case octave_value::op_el_not_or: | |
2884 return binary_op (ti, octave_value::op_el_or, | |
2885 unary_op (octave_value::op_not, v1), v2); | |
2886 | |
2887 case octave_value::op_el_and_not: | |
2888 return binary_op (ti, octave_value::op_el_and, | |
2889 v1, unary_op (octave_value::op_not, v2)); | |
2890 | |
2891 case octave_value::op_el_or_not: | |
2892 return binary_op (ti, octave_value::op_el_or, | |
2893 v1, unary_op (octave_value::op_not, v2)); | |
2894 | |
2895 default: | |
2896 error ("invalid compound operator"); | |
2897 } | |
2898 } | |
2899 | |
2900 octave_value | |
2901 binary_op (type_info& ti, octave_value::compound_binary_op op, | |
2902 const octave_value& v1, const octave_value& v2) | |
2903 { | |
2904 octave_value retval; | |
2905 | |
2906 int t1 = v1.type_id (); | |
2907 int t2 = v2.type_id (); | |
2908 | |
2909 if (t1 == octave_class::static_type_id () | |
2910 || t2 == octave_class::static_type_id () | |
2911 || t1 == octave_classdef::static_type_id () | |
2912 || t2 == octave_classdef::static_type_id ()) | |
2913 { | |
2914 type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op); | |
2915 | |
2916 if (f) | |
2917 retval = f (v1, v2); | |
2918 else | |
2919 retval = decompose_binary_op (ti, op, v1, v2); | |
2920 } | |
2921 else | |
2922 { | |
2923 type_info::binary_op_fcn f = ti.lookup_binary_op (op, t1, t2); | |
2924 | |
2925 if (f) | |
2926 retval = f (v1.get_rep (), v2.get_rep ()); | |
2927 else | |
2928 retval = decompose_binary_op (ti, op, v1, v2); | |
2929 } | |
2930 | |
2931 return retval; | |
2932 } | |
2933 | |
2934 octave_value | |
2935 binary_op (octave_value::compound_binary_op op, | |
2936 const octave_value& v1, const octave_value& v2) | |
2937 { | |
2938 type_info& ti = __get_type_info__ (); | |
2939 | |
2940 return binary_op (ti, op, v1, v2); | |
2941 } | |
2942 | |
2943 OCTAVE_NORETURN static void | |
2944 err_cat_op (const std::string& tn1, const std::string& tn2) | |
2945 { | |
2946 error ("concatenation operator not implemented for '%s' by '%s' operations", | |
2947 tn1.c_str (), tn2.c_str ()); | |
2948 } | |
2949 | |
2950 OCTAVE_NORETURN static void | |
2951 err_cat_op_conv (void) | |
2952 { | |
2953 error ("type conversion failed for concatenation operator"); | |
2954 } | |
2955 | |
2956 octave_value | |
2957 cat_op (type_info& ti, const octave_value& v1, | |
2958 const octave_value& v2, const Array<octave_idx_type>& ra_idx) | |
2959 { | |
2960 octave_value retval; | |
2961 | |
2962 // Can't rapid return for concatenation with an empty object here as | |
2963 // something like cat(1,[],single([]) must return the correct type. | |
2964 | |
2965 int t1 = v1.type_id (); | |
2966 int t2 = v2.type_id (); | |
2967 | |
2968 type_info::cat_op_fcn f = ti.lookup_cat_op (t1, t2); | |
2969 | |
2970 if (f) | |
2971 retval = f (v1.get_rep (), v2.get_rep (), ra_idx); | |
2972 else | |
2973 { | |
2974 octave_value tv1; | |
2975 octave_base_value::type_conv_info cf1 = v1.numeric_conversion_function (); | |
2976 | |
2977 octave_value tv2; | |
2978 octave_base_value::type_conv_info cf2 = v2.numeric_conversion_function (); | |
2979 | |
2980 // Try biased (one-sided) conversions first. | |
2981 if (cf2.type_id () >= 0 && ti.lookup_cat_op (t1, cf2.type_id ())) | |
2982 cf1 = nullptr; | |
2983 else if (cf1.type_id () >= 0 && ti.lookup_cat_op (cf1.type_id (), t2)) | |
2984 cf2 = nullptr; | |
2985 | |
2986 if (cf1) | |
2987 { | |
2988 octave_base_value *tmp = cf1 (v1.get_rep ()); | |
2989 | |
2990 if (! tmp) | |
2991 err_cat_op_conv (); | |
2992 | |
2993 tv1 = octave_value (tmp); | |
2994 t1 = tv1.type_id (); | |
2995 } | |
2996 else | |
2997 tv1 = v1; | |
2998 | |
2999 if (cf2) | |
3000 { | |
3001 octave_base_value *tmp = cf2 (v2.get_rep ()); | |
3002 | |
3003 if (! tmp) | |
3004 err_cat_op_conv (); | |
3005 | |
3006 tv2 = octave_value (tmp); | |
3007 t2 = tv2.type_id (); | |
3008 } | |
3009 else | |
3010 tv2 = v2; | |
3011 | |
3012 if (! cf1 && ! cf2) | |
3013 err_cat_op (v1.type_name (), v2.type_name ()); | |
3014 | |
3015 retval = cat_op (ti, tv1, tv2, ra_idx); | |
3016 } | |
3017 | |
3018 return retval; | |
3019 } | |
3020 | |
3021 octave_value | |
3022 cat_op (const octave_value& v1, const octave_value& v2, | |
3023 const Array<octave_idx_type>& ra_idx) | |
3024 { | |
3025 type_info& ti = __get_type_info__ (); | |
3026 | |
3027 return cat_op (ti, v1, v2, ra_idx); | |
3028 } | |
3029 | |
3030 // Unless the colon operator is used with a class or classdef object, | |
3031 // then all arguments must be the same type or mixed with double | |
3032 // values. | |
3033 | |
3034 static builtin_type_t | |
3035 get_colon_op_type (builtin_type_t op1_type, builtin_type_t op2_type) | |
3036 { | |
3037 if (op1_type == op2_type) | |
3038 return op1_type; | |
3039 | |
3040 if (op1_type == btyp_double) | |
3041 return op2_type; | |
3042 | |
3043 if (op2_type == btyp_double) | |
3044 return op1_type; | |
3045 | |
3046 return btyp_unknown; | |
3047 } | |
3048 | |
3049 static builtin_type_t | |
3050 get_colon_op_type (const octave_value& base, const octave_value& increment, | |
3051 const octave_value& limit) | |
3052 { | |
3053 builtin_type_t typ | |
3054 = get_colon_op_type (base.builtin_type (), increment.builtin_type ()); | |
3055 | |
3056 if (typ == btyp_unknown) | |
3057 return typ; | |
3058 | |
3059 return get_colon_op_type (typ, limit.builtin_type ()); | |
3060 } | |
3061 | |
3062 // This check depends on the type of VAL either being the expected | |
3063 // integer type or a double value. | |
3064 | |
3065 template <typename T> | |
3066 static void | |
3067 check_colon_operand (const octave_value& val, const char *op_str) | |
3068 { | |
3069 if (! val.is_double_type ()) | |
3070 return; | |
3071 | |
3072 double dval = val.double_value (); | |
3073 double intpart; | |
3074 static const double out_of_range_top | |
3075 = static_cast<double> (std::numeric_limits<typename T::val_type>::max ()) | |
3076 + 1.; | |
3077 | |
3078 if (dval >= out_of_range_top | |
3079 || dval < std::numeric_limits<typename T::val_type>::min () | |
3080 || std::modf (dval, &intpart) != 0.0) | |
3081 error ("colon operator %s invalid (not an integer or out of range for given integer type)", op_str); | |
3082 } | |
3083 | |
3084 // Return the difference between two unsigned integers as an unsigned | |
3085 // integer of the same type. | |
3086 | |
3087 template <typename UT, | |
3088 typename std::enable_if<(std::is_integral<UT>::value | |
3089 && std::is_unsigned<UT>::value), | |
3090 bool>::type = true> | |
3091 UT | |
3092 integer_difference (UT a, UT b) | |
3093 { | |
3094 return a > b ? a - b : b - a; | |
3095 } | |
3096 | |
3097 // Return the difference between two signed integers as an unsigned | |
3098 // integer corresponding to the signed type. | |
3099 | |
3100 template <typename ST, | |
3101 typename UT = typename std::make_unsigned<ST>::type, | |
3102 typename std::enable_if<(std::is_integral<ST>::value | |
3103 && std::is_signed<ST>::value), | |
3104 bool>::type = true> | |
3105 UT | |
3106 integer_difference (ST a, ST b) | |
3107 { | |
3108 // Map to unsigned. | |
3109 // Idea from https://stackoverflow.com/questions/10589559 | |
3110 | |
3111 static const UT offset | |
3112 = UT (0) - static_cast<UT> (std::numeric_limits<ST>::min ()); | |
3113 | |
3114 UT au = static_cast<UT> (a) + offset; | |
3115 UT bu = static_cast<UT> (b) + offset; | |
3116 | |
3117 return integer_difference (au, bu); | |
3118 } | |
3119 | |
3120 // Number of elements in an integer range taking care to avoid | |
3121 // overflow. Base and limit are of the same type. If they are | |
3122 // unsigned, then increment is also of the same type. If they are | |
3123 // signed, then the type of increment is the unsigned type | |
3124 // corresponding to T. Assumes that the base and limit values are | |
3125 // consistent with the sign of the original increment (not an empty | |
3126 // range) so we can calculate numel with the absolute value of the | |
3127 // increment and the absolute difference between the base and limit | |
3128 // values. | |
3129 | |
3130 template <typename T, | |
3131 typename UT = typename std::make_unsigned<T>::type, | |
3132 typename std::enable_if<std::is_integral<T>::value, | |
3133 bool>::type = true> | |
3134 octave_idx_type | |
3135 range_numel_aux (T base, UT unsigned_increment, T limit) | |
3136 { | |
3137 // Adding one to DIFF/INCREMENT may overflow, so check whether it is | |
3138 // out of range before adding. | |
3139 | |
3140 UT nel_m1 = integer_difference (limit, base) / unsigned_increment; | |
3141 | |
3142 // FIXME: fix error message. | |
3143 if (nel_m1 > std::numeric_limits<octave_idx_type>::max () - 1) | |
3144 error ("too many elements for range!"); | |
3145 | |
3146 return static_cast<octave_idx_type> (nel_m1) + 1; | |
3147 } | |
3148 | |
3149 // Convert signed range increment to unsigned. | |
3150 | |
3151 template <typename ST, | |
3152 typename UT = typename std::make_unsigned<ST>::type, | |
3153 typename std::enable_if<(std::is_integral<ST>::value | |
3154 && std::is_signed<ST>::value), | |
3155 bool>::type = true> | |
3156 UT | |
3157 range_increment (ST increment) | |
3158 { | |
3159 return (increment < 0 | |
3160 ? UT (0) - static_cast<UT> (increment) | |
3161 : static_cast<UT> (increment)); | |
3162 } | |
3163 | |
3164 // "Convert" unsigned range increment to unsigned. A no-op, but | |
3165 // needed to provide a consistent interface for other template | |
3166 // functions. | |
3167 | |
3168 template <typename T, | |
3169 typename UT = typename std::make_unsigned<T>::type, | |
3170 typename std::enable_if<(std::is_integral<UT>::value | |
3171 && std::is_unsigned<UT>::value), | |
3172 bool>::type = true> | |
3173 UT | |
3174 range_increment (UT increment) | |
3175 { | |
3176 return increment; | |
3177 } | |
3178 | |
3179 // Convert double range increment to unsigned. Enable by return type. | |
3180 | |
3181 template <typename T, | |
3182 typename UT = typename std::make_unsigned<T>::type> | |
3183 typename std::enable_if<(std::is_integral<UT>::value | |
3184 && std::is_unsigned<UT>::value), UT>::type | |
3185 range_increment (double increment) | |
3186 { | |
3187 double abs_increment = std::abs (increment); | |
3188 | |
3189 return static_cast<UT> (abs_increment); | |
3190 } | |
3191 | |
3192 // Number of elements in an integer range base:increment:limit. Base, | |
3193 // increment, and limit are of the same signed type. | |
3194 | |
3195 template <typename ST, | |
3196 typename std::enable_if<(std::is_integral<ST>::value | |
3197 && std::is_signed<ST>::value), | |
3198 bool>::type = true> | |
3199 octave_idx_type | |
3200 range_numel (ST base, ST increment, ST limit) | |
3201 { | |
3202 typedef typename std::make_unsigned<ST>::type UT; | |
3203 | |
3204 if (increment == 0 | |
3205 || (increment > 0 && base > limit) | |
3206 || (increment < 0 && base < limit)) | |
3207 return 0; | |
3208 | |
3209 UT unsigned_increment = range_increment<ST> (increment); | |
3210 | |
3211 return range_numel_aux (base, unsigned_increment, limit); | |
3212 } | |
3213 | |
3214 // Number of elements in an integer range base:increment:limit. Base, | |
3215 // increment, and limit are unsigned and of the same type. | |
3216 | |
3217 template <typename UT, | |
3218 typename std::enable_if<(std::is_integral<UT>::value | |
3219 && std::is_unsigned<UT>::value), | |
3220 bool>::type = true> | |
3221 octave_idx_type | |
3222 range_numel (UT base, UT increment, UT limit) | |
3223 { | |
3224 // Unsigned, INCREMENT is always >= 0. | |
3225 if (increment == 0 || base > limit) | |
3226 return 0; | |
3227 | |
3228 return range_numel_aux (base, increment, limit); | |
3229 } | |
3230 | |
3231 // Number of elements in an integer range base:increment:limit. Base | |
3232 // and limit are of the same type and increment is a double value. | |
3233 | |
3234 template <typename T, | |
3235 typename UT = typename std::make_unsigned<T>::type, | |
3236 typename std::enable_if<std::is_integral<T>::value, | |
3237 bool>::type = true> | |
3238 octave_idx_type | |
3239 range_numel (T base, double increment, T limit) | |
3240 { | |
3241 double intpart; | |
3242 if (math::isnan (increment) || std::modf (increment, &intpart) != 0.0) | |
3243 error ("colon operator increment invalid (not an integer)"); | |
3244 | |
3245 if (increment == 0 | |
3246 || (increment > 0 && base > limit) | |
3247 || (increment < 0 && base < limit)) | |
3248 return 0; | |
3249 | |
3250 static const double out_of_range_top | |
3251 = static_cast<double> (std::numeric_limits<UT>::max ()) + 1.; | |
3252 | |
3253 double abs_increment = std::abs (increment); | |
3254 | |
3255 // Technically, this condition should be | |
3256 // `abs_increment > std::numeric_limits<UT>::max ()`. | |
3257 // But intmax('uint64') is not representable exactly as floating point | |
3258 // number. Instead, it "rounds" up by 1 to 2^64. To account for | |
3259 // this, use the following expression which works for all unsigned | |
3260 // integer types. | |
3261 if (abs_increment >= out_of_range_top) | |
3262 return 1; | |
3263 | |
3264 UT unsigned_increment = range_increment<T> (increment); | |
3265 | |
3266 return range_numel_aux (base, unsigned_increment, limit); | |
3267 } | |
3268 | |
3269 // Make a range from integer values. Increment may be integer or double. | |
3270 | |
3271 template <typename T, | |
3272 typename IT, | |
3273 typename std::enable_if<(std::is_integral<T>::value | |
3274 && std::is_arithmetic<IT>::value), | |
3275 bool>::type = true> | |
3276 octave_value | |
3277 make_int_range (T base, IT increment, T limit) | |
3278 { | |
3279 octave_idx_type nel = range_numel (base, increment, limit); | |
3280 | |
3281 // For now, we create arrays instead of range<T> for all types | |
3282 // except double. | |
3283 | |
3284 Array<octave_int<T>> result (dim_vector (1, nel)); | |
3285 | |
3286 if (nel > 0) | |
3287 { | |
3288 typedef typename std::make_unsigned<T>::type UT; | |
3289 | |
3290 UT unsigned_increment = range_increment<T> (increment); | |
3291 | |
3292 T val = base; | |
3293 result.xelem (0) = val; | |
3294 | |
3295 if (limit > base) | |
3296 { | |
3297 for (octave_idx_type i = 1; i < nel; i++) | |
3298 { | |
3299 val += unsigned_increment; | |
3300 result.xelem (i) = val; | |
3301 } | |
3302 } | |
3303 else | |
3304 { | |
3305 for (octave_idx_type i = 1; i < nel; i++) | |
3306 { | |
3307 val -= unsigned_increment; | |
3308 result.xelem (i) = val; | |
3309 } | |
3310 } | |
3311 } | |
3312 | |
3313 return octave_value (result); | |
3314 } | |
3315 | |
3316 // Make a range from floating point values. | |
3317 | |
3318 // FIXME: Try again to define memory efficient range classes for | |
3319 // integer and floating point values? Maybe with the templates | |
3320 // defined in this file we could do that in a reasonable way? | |
3321 // Regardless of that, it might be good to provide special treatment | |
3322 // of colon expressions in FOR loops so that we can eliminate the | |
3323 // "is_for_cmd_expr / force_range" flag from the parser and the | |
3324 // octave_value constructors for range objects. | |
3325 | |
3326 // NOTE: We define this function separately for float and double so | |
3327 // that we can avoid having to instantiate ov_range<float>. We DO | |
3328 // instantiate range<float> but only so we can take advantage of the | |
3329 // range<T> class to generate the corresponding array of float values | |
3330 // and not have to duplicate that code here. | |
3331 | |
3332 template <typename T, | |
3333 typename std::enable_if<std::is_same<T, double>::value, | |
3334 bool>::type = true> | |
3335 octave_value | |
3336 make_float_range (T base, T increment, T limit, bool is_for_cmd_expr) | |
3337 { | |
3338 if (math::isnan (base) | |
3339 || math::isnan (increment) | |
3340 || math::isnan (limit)) | |
3341 return octave_value (numeric_limits<T>::NaN ()); | |
3342 | |
3343 if (increment == 0 | |
3344 || (increment > 0 && base > limit) | |
3345 || (increment < 0 && base < limit)) | |
3346 return octave_value (Array<T> (dim_vector (1, 0))); | |
3347 | |
3348 // At this point, we know that the base and limit values are | |
3349 // consistent with the sign of the increment (not an empty range). | |
3350 | |
3351 range<T> r (base, increment, limit); | |
3352 | |
3353 if (! is_for_cmd_expr && ! r.is_storable ()) | |
3354 error ("range with infinite number of elements cannot be stored"); | |
3355 | |
3356 return octave_value (r, is_for_cmd_expr); | |
3357 } | |
3358 | |
3359 template <typename T, | |
3360 typename std::enable_if<std::is_same<T, float>::value, | |
3361 bool>::type = true> | |
3362 octave_value | |
3363 make_float_range (T base, T increment, T limit, bool is_for_cmd_expr) | |
3364 { | |
3365 if (math::isnan (base) | |
3366 || math::isnan (increment) | |
3367 || math::isnan (limit)) | |
3368 return octave_value (numeric_limits<T>::NaN ()); | |
3369 | |
3370 if (increment == 0 | |
3371 || (increment > 0 && base > limit) | |
3372 || (increment < 0 && base < limit)) | |
3373 return octave_value (Array<T> (dim_vector (1, 0))); | |
3374 | |
3375 // At this point, we know that the base and limit values are | |
3376 // consistent with the sign of the increment (not an empty range). | |
3377 | |
3378 range<T> r (base, increment, limit); | |
3379 | |
3380 if (! is_for_cmd_expr && ! r.is_storable ()) | |
3381 error ("range with infinite number of elements cannot be stored"); | |
3382 | |
3383 return octave_value (r.array_value ()); | |
3384 } | |
3385 | |
3386 template <typename T, | |
3387 typename std::enable_if<(std::is_same<T, octave_int8>::value | |
3388 || std::is_same<T, octave_uint8>::value | |
3389 || std::is_same<T, octave_int16>::value | |
3390 || std::is_same<T, octave_uint16>::value | |
3391 || std::is_same<T, octave_int32>::value | |
3392 || std::is_same<T, octave_uint32>::value | |
3393 || std::is_same<T, octave_int64>::value | |
3394 || std::is_same<T, octave_uint64>::value), | |
3395 bool>::type = true> | |
3396 octave_value | |
3397 make_int_range (const octave_value& base, const octave_value& increment, | |
3398 const octave_value& limit) | |
3399 { | |
3400 if (base.isempty () || increment.isempty () || limit.isempty ()) | |
3401 return octave_value (Array<T> (dim_vector (1, 0))); | |
3402 | |
3403 check_colon_operand<T> (base, "lower bound"); | |
3404 check_colon_operand<T> (limit, "upper bound"); | |
3405 | |
3406 typename T::val_type base_val = octave_value_extract<T> (base).value (); | |
3407 typename T::val_type limit_val = octave_value_extract<T> (limit).value (); | |
3408 | |
3409 if (increment.is_double_type ()) | |
3410 { | |
3411 double increment_val = increment.double_value (); | |
3412 | |
3413 return make_int_range (base_val, increment_val, limit_val); | |
3414 } | |
3415 | |
3416 check_colon_operand<T> (increment, "increment"); | |
3417 | |
3418 typename T::val_type increment_val | |
3419 = octave_value_extract<T> (increment).value (); | |
3420 | |
3421 return make_int_range (base_val, increment_val, limit_val); | |
3422 } | |
3423 | |
3424 template <typename T, | |
3425 typename std::enable_if<std::is_floating_point<T>::value, | |
3426 bool>::type = true> | |
3427 octave_value | |
3428 make_float_range (const octave_value& base, const octave_value& increment, | |
3429 const octave_value& limit, bool is_for_cmd_expr) | |
3430 { | |
3431 if (base.isempty () || increment.isempty () || limit.isempty ()) | |
3432 return octave_value (Array<T> (dim_vector (1, 0))); | |
3433 | |
3434 T base_val = octave_value_extract<T> (base); | |
3435 T increment_val = octave_value_extract<T> (increment); | |
3436 T limit_val = octave_value_extract<T> (limit); | |
3437 | |
3438 return make_float_range (base_val, increment_val, limit_val, | |
3439 is_for_cmd_expr); | |
3440 } | |
3441 | |
3442 | |
3443 octave_value | |
3444 make_char_range (const octave_value& base, const octave_value& increment, | |
3445 const octave_value& limit) | 3055 const octave_value& limit) |
3446 { | 3056 { |
3447 octave_value retval; | 3057 builtin_type_t typ |
3448 | 3058 = get_colon_op_type (base.builtin_type (), increment.builtin_type ()); |
3449 bool dq_str = (base.is_dq_string () || increment.is_dq_string () | 3059 |
3450 || limit.is_dq_string ()); | 3060 if (typ == btyp_unknown) |
3451 | 3061 return typ; |
3452 char type = dq_str ? '"' : '\''; | 3062 |
3453 | 3063 return get_colon_op_type (typ, limit.builtin_type ()); |
3454 if (base.isempty () || increment.isempty () || limit.isempty ()) | 3064 } |
3455 retval = octave_value ("", type); | 3065 |
3456 else | 3066 // This check depends on the type of VAL either being the expected |
3457 { | 3067 // integer type or a double value. |
3458 Matrix mtx_base = base.matrix_value (true); | 3068 |
3459 Matrix mtx_increment = increment.matrix_value (true); | 3069 template <typename T> |
3460 Matrix mtx_limit = limit.matrix_value (true); | 3070 static void |
3461 | 3071 check_colon_operand (const octave_value& val, const char *op_str) |
3462 range<double> tmp (mtx_base(0), mtx_increment(0), mtx_limit(0)); | 3072 { |
3463 | 3073 if (! val.is_double_type ()) |
3464 retval = octave_value (tmp); | 3074 return; |
3465 } | 3075 |
3466 | 3076 double dval = val.double_value (); |
3467 return retval.convert_to_str (false, true, type); | 3077 double intpart; |
3468 } | 3078 static const double out_of_range_top |
3469 | 3079 = static_cast<double> (std::numeric_limits<typename T::val_type>::max ()) |
3470 octave_value | 3080 + 1.; |
3471 colon_op (const octave_value& base, const octave_value& increment_arg, | 3081 |
3472 const octave_value& limit, bool is_for_cmd_expr) | 3082 if (dval >= out_of_range_top |
3473 { | 3083 || dval < std::numeric_limits<typename T::val_type>::min () |
3474 if (base.isobject () || increment_arg.isobject () || limit.isobject ()) | 3084 || std::modf (dval, &intpart) != 0.0) |
3475 { | 3085 error ("colon operator %s invalid (not an integer or out of range for given integer type)", op_str); |
3476 octave_value_list tmp1; | 3086 } |
3477 | 3087 |
3478 if (increment_arg.is_defined ()) | 3088 // Return the difference between two unsigned integers as an unsigned |
3479 { | 3089 // integer of the same type. |
3480 tmp1(2) = limit; | 3090 |
3481 tmp1(1) = increment_arg; | 3091 template <typename UT, |
3482 tmp1(0) = base; | 3092 typename std::enable_if<(std::is_integral<UT>::value |
3483 } | 3093 && std::is_unsigned<UT>::value), |
3484 else | 3094 bool>::type = true> |
3485 { | 3095 UT |
3486 tmp1(1) = limit; | 3096 integer_difference (UT a, UT b) |
3487 tmp1(0) = base; | 3097 { |
3488 } | 3098 return a > b ? a - b : b - a; |
3489 | 3099 } |
3490 interpreter& interp = __get_interpreter__ (); | 3100 |
3491 | 3101 // Return the difference between two signed integers as an unsigned |
3492 symbol_table& symtab = interp.get_symbol_table (); | 3102 // integer corresponding to the signed type. |
3493 | 3103 |
3494 octave_value fcn = symtab.find_function ("colon", tmp1); | 3104 template <typename ST, |
3495 | 3105 typename UT = typename std::make_unsigned<ST>::type, |
3496 if (fcn.is_defined ()) | 3106 typename std::enable_if<(std::is_integral<ST>::value |
3497 { | 3107 && std::is_signed<ST>::value), |
3498 octave_value_list tmp2 = interp.feval (fcn, tmp1, 1); | 3108 bool>::type = true> |
3499 | 3109 UT |
3500 return tmp2(0); | 3110 integer_difference (ST a, ST b) |
3501 } | 3111 { |
3502 } | 3112 // Map to unsigned. |
3503 | 3113 // Idea from https://stackoverflow.com/questions/10589559 |
3504 octave_value increment | 3114 |
3505 = increment_arg.is_defined () ? increment_arg : octave_value (1.0); | 3115 static const UT offset |
3506 | 3116 = UT (0) - static_cast<UT> (std::numeric_limits<ST>::min ()); |
3507 if (base.numel () > 1 || limit.numel () > 1 || increment.numel () > 1) | 3117 |
3508 warning_with_id ("Octave:colon-nonscalar-argument", | 3118 UT au = static_cast<UT> (a) + offset; |
3509 "colon arguments should be scalars"); | 3119 UT bu = static_cast<UT> (b) + offset; |
3510 | 3120 |
3511 if (base.iscomplex () || limit.iscomplex () || increment.iscomplex ()) | 3121 return integer_difference (au, bu); |
3512 warning_with_id ("Octave:colon-complex-argument", | 3122 } |
3513 "imaginary part of complex colon arguments is ignored"); | 3123 |
3514 | 3124 // Number of elements in an integer range taking care to avoid |
3515 // FIXME: is there a better way to do this job, maybe using type traits? | 3125 // overflow. Base and limit are of the same type. If they are |
3516 | 3126 // unsigned, then increment is also of the same type. If they are |
3517 builtin_type_t type_id = get_colon_op_type (base, increment, limit); | 3127 // signed, then the type of increment is the unsigned type |
3518 | 3128 // corresponding to T. Assumes that the base and limit values are |
3519 // For compatibility with Matlab, don't allow the range used in | 3129 // consistent with the sign of the original increment (not an empty |
3520 // a FOR loop expression to be converted to a Matrix. | 3130 // range) so we can calculate numel with the absolute value of the |
3521 | 3131 // increment and the absolute difference between the base and limit |
3522 // For now, these functions create arrays instead of range<T> for | 3132 // values. |
3523 // all types except double. | 3133 |
3524 | 3134 template <typename T, |
3525 switch (type_id) | 3135 typename UT = typename std::make_unsigned<T>::type, |
3526 { | 3136 typename std::enable_if<std::is_integral<T>::value, |
3527 case btyp_double: | 3137 bool>::type = true> |
3528 case btyp_complex: | 3138 octave_idx_type |
3529 return make_float_range<double> (base, increment, limit, is_for_cmd_expr); | 3139 range_numel_aux (T base, UT unsigned_increment, T limit) |
3530 | 3140 { |
3531 case btyp_float: | 3141 // Adding one to DIFF/INCREMENT may overflow, so check whether it is |
3532 case btyp_float_complex: | 3142 // out of range before adding. |
3533 return make_float_range<float> (base, increment, limit, is_for_cmd_expr); | 3143 |
3534 | 3144 UT nel_m1 = integer_difference (limit, base) / unsigned_increment; |
3535 case btyp_int8: | 3145 |
3536 return make_int_range<octave_int8> (base, increment, limit); | 3146 // FIXME: fix error message. |
3537 | 3147 if (nel_m1 > std::numeric_limits<octave_idx_type>::max () - 1) |
3538 case btyp_int16: | 3148 error ("too many elements for range!"); |
3539 return make_int_range<octave_int16> (base, increment, limit); | 3149 |
3540 | 3150 return static_cast<octave_idx_type> (nel_m1) + 1; |
3541 case btyp_int32: | 3151 } |
3542 return make_int_range<octave_int32> (base, increment, limit); | 3152 |
3543 | 3153 // Convert signed range increment to unsigned. |
3544 case btyp_int64: | 3154 |
3545 return make_int_range<octave_int64> (base, increment, limit); | 3155 template <typename ST, |
3546 | 3156 typename UT = typename std::make_unsigned<ST>::type, |
3547 case btyp_uint8: | 3157 typename std::enable_if<(std::is_integral<ST>::value |
3548 return make_int_range<octave_uint8> (base, increment, limit); | 3158 && std::is_signed<ST>::value), |
3549 | 3159 bool>::type = true> |
3550 case btyp_uint16: | 3160 UT |
3551 return make_int_range<octave_uint16> (base, increment, limit); | 3161 range_increment (ST increment) |
3552 | 3162 { |
3553 case btyp_uint32: | 3163 return (increment < 0 |
3554 return make_int_range<octave_uint32> (base, increment, limit); | 3164 ? UT (0) - static_cast<UT> (increment) |
3555 | 3165 : static_cast<UT> (increment)); |
3556 case btyp_uint64: | 3166 } |
3557 return make_int_range<octave_uint64> (base, increment, limit); | 3167 |
3558 | 3168 // "Convert" unsigned range increment to unsigned. A no-op, but |
3559 case btyp_char: | 3169 // needed to provide a consistent interface for other template |
3560 return make_char_range (base, increment, limit); | 3170 // functions. |
3561 | 3171 |
3562 case btyp_unknown: | 3172 template <typename T, |
3563 error ("incompatible types found in range expression"); | 3173 typename UT = typename std::make_unsigned<T>::type, |
3564 | 3174 typename std::enable_if<(std::is_integral<UT>::value |
3565 default: | 3175 && std::is_unsigned<UT>::value), |
3566 error ("invalid types found in range expression"); | 3176 bool>::type = true> |
3567 } | 3177 UT |
3568 | 3178 range_increment (UT increment) |
3569 return octave_value (); | 3179 { |
3570 } | 3180 return increment; |
3571 | 3181 } |
3572 OCTAVE_NORETURN static void | 3182 |
3573 err_unary_op_conv (const std::string& on) | 3183 // Convert double range increment to unsigned. Enable by return type. |
3574 { | 3184 |
3575 error ("type conversion failed for unary operator '%s'", on.c_str ()); | 3185 template <typename T, |
3576 } | 3186 typename UT = typename std::make_unsigned<T>::type> |
3577 | 3187 typename std::enable_if<(std::is_integral<UT>::value |
3578 octave_value | 3188 && std::is_unsigned<UT>::value), UT>::type |
3579 unary_op (type_info& ti, octave_value::unary_op op, | 3189 range_increment (double increment) |
3580 const octave_value& v) | 3190 { |
3581 { | 3191 double abs_increment = std::abs (increment); |
3582 octave_value retval; | 3192 |
3583 | 3193 return static_cast<UT> (abs_increment); |
3584 int t = v.type_id (); | 3194 } |
3585 | 3195 |
3586 if (t == octave_class::static_type_id () | 3196 // Number of elements in an integer range base:increment:limit. Base, |
3587 || t == octave_classdef::static_type_id ()) | 3197 // increment, and limit are of the same signed type. |
3588 { | 3198 |
3589 type_info::unary_class_op_fcn f = ti.lookup_unary_class_op (op); | 3199 template <typename ST, |
3590 | 3200 typename std::enable_if<(std::is_integral<ST>::value |
3591 if (! f) | 3201 && std::is_signed<ST>::value), |
3592 err_unary_op (octave_value::unary_op_as_string (op), v.class_name ()); | 3202 bool>::type = true> |
3593 | 3203 octave_idx_type |
3594 retval = f (v); | 3204 range_numel (ST base, ST increment, ST limit) |
3595 } | 3205 { |
3596 else | 3206 typedef typename std::make_unsigned<ST>::type UT; |
3597 { | 3207 |
3598 // FIXME: we need to handle overloading operators for built-in | 3208 if (increment == 0 |
3599 // classes (double, char, int8, etc.) | 3209 || (increment > 0 && base > limit) |
3600 | 3210 || (increment < 0 && base < limit)) |
3601 type_info::unary_op_fcn f = ti.lookup_unary_op (op, t); | 3211 return 0; |
3602 | 3212 |
3603 if (f) | 3213 UT unsigned_increment = range_increment<ST> (increment); |
3604 retval = f (v.get_rep ()); | 3214 |
3605 else | 3215 return range_numel_aux (base, unsigned_increment, limit); |
3606 { | 3216 } |
3607 octave_value tv; | 3217 |
3608 octave_base_value::type_conv_fcn cf | 3218 // Number of elements in an integer range base:increment:limit. Base, |
3609 = v.numeric_conversion_function (); | 3219 // increment, and limit are unsigned and of the same type. |
3610 | 3220 |
3611 if (! cf) | 3221 template <typename UT, |
3612 err_unary_op (octave_value::unary_op_as_string (op), | 3222 typename std::enable_if<(std::is_integral<UT>::value |
3613 v.type_name ()); | 3223 && std::is_unsigned<UT>::value), |
3614 | 3224 bool>::type = true> |
3615 octave_base_value *tmp = cf (v.get_rep ()); | 3225 octave_idx_type |
3616 | 3226 range_numel (UT base, UT increment, UT limit) |
3617 if (! tmp) | 3227 { |
3618 err_unary_op_conv (octave_value::unary_op_as_string (op)); | 3228 // Unsigned, INCREMENT is always >= 0. |
3619 | 3229 if (increment == 0 || base > limit) |
3620 tv = octave_value (tmp); | 3230 return 0; |
3621 retval = unary_op (op, tv); | 3231 |
3622 } | 3232 return range_numel_aux (base, increment, limit); |
3623 } | 3233 } |
3624 | 3234 |
3625 return retval; | 3235 // Number of elements in an integer range base:increment:limit. Base |
3626 } | 3236 // and limit are of the same type and increment is a double value. |
3627 | 3237 |
3628 octave_value | 3238 template <typename T, |
3629 unary_op (octave_value::unary_op op, const octave_value& v) | 3239 typename UT = typename std::make_unsigned<T>::type, |
3630 { | 3240 typename std::enable_if<std::is_integral<T>::value, |
3631 type_info& ti = __get_type_info__ (); | 3241 bool>::type = true> |
3632 | 3242 octave_idx_type |
3633 return unary_op (ti, op, v); | 3243 range_numel (T base, double increment, T limit) |
3634 } | 3244 { |
3245 double intpart; | |
3246 if (math::isnan (increment) || std::modf (increment, &intpart) != 0.0) | |
3247 error ("colon operator increment invalid (not an integer)"); | |
3248 | |
3249 if (increment == 0 | |
3250 || (increment > 0 && base > limit) | |
3251 || (increment < 0 && base < limit)) | |
3252 return 0; | |
3253 | |
3254 static const double out_of_range_top | |
3255 = static_cast<double> (std::numeric_limits<UT>::max ()) + 1.; | |
3256 | |
3257 double abs_increment = std::abs (increment); | |
3258 | |
3259 // Technically, this condition should be | |
3260 // `abs_increment > std::numeric_limits<UT>::max ()`. | |
3261 // But intmax('uint64') is not representable exactly as floating point | |
3262 // number. Instead, it "rounds" up by 1 to 2^64. To account for | |
3263 // this, use the following expression which works for all unsigned | |
3264 // integer types. | |
3265 if (abs_increment >= out_of_range_top) | |
3266 return 1; | |
3267 | |
3268 UT unsigned_increment = range_increment<T> (increment); | |
3269 | |
3270 return range_numel_aux (base, unsigned_increment, limit); | |
3271 } | |
3272 | |
3273 // Make a range from integer values. Increment may be integer or double. | |
3274 | |
3275 template <typename T, | |
3276 typename IT, | |
3277 typename std::enable_if<(std::is_integral<T>::value | |
3278 && std::is_arithmetic<IT>::value), | |
3279 bool>::type = true> | |
3280 octave_value | |
3281 make_int_range (T base, IT increment, T limit) | |
3282 { | |
3283 octave_idx_type nel = range_numel (base, increment, limit); | |
3284 | |
3285 // For now, we create arrays instead of range<T> for all types | |
3286 // except double. | |
3287 | |
3288 Array<octave_int<T>> result (dim_vector (1, nel)); | |
3289 | |
3290 if (nel > 0) | |
3291 { | |
3292 typedef typename std::make_unsigned<T>::type UT; | |
3293 | |
3294 UT unsigned_increment = range_increment<T> (increment); | |
3295 | |
3296 T val = base; | |
3297 result.xelem (0) = val; | |
3298 | |
3299 if (limit > base) | |
3300 { | |
3301 for (octave_idx_type i = 1; i < nel; i++) | |
3302 { | |
3303 val += unsigned_increment; | |
3304 result.xelem (i) = val; | |
3305 } | |
3306 } | |
3307 else | |
3308 { | |
3309 for (octave_idx_type i = 1; i < nel; i++) | |
3310 { | |
3311 val -= unsigned_increment; | |
3312 result.xelem (i) = val; | |
3313 } | |
3314 } | |
3315 } | |
3316 | |
3317 return octave_value (result); | |
3318 } | |
3319 | |
3320 // Make a range from floating point values. | |
3321 | |
3322 // FIXME: Try again to define memory efficient range classes for | |
3323 // integer and floating point values? Maybe with the templates | |
3324 // defined in this file we could do that in a reasonable way? | |
3325 // Regardless of that, it might be good to provide special treatment | |
3326 // of colon expressions in FOR loops so that we can eliminate the | |
3327 // "is_for_cmd_expr / force_range" flag from the parser and the | |
3328 // octave_value constructors for range objects. | |
3329 | |
3330 // NOTE: We define this function separately for float and double so | |
3331 // that we can avoid having to instantiate ov_range<float>. We DO | |
3332 // instantiate range<float> but only so we can take advantage of the | |
3333 // range<T> class to generate the corresponding array of float values | |
3334 // and not have to duplicate that code here. | |
3335 | |
3336 template <typename T, | |
3337 typename std::enable_if<std::is_same<T, double>::value, | |
3338 bool>::type = true> | |
3339 octave_value | |
3340 make_float_range (T base, T increment, T limit, bool is_for_cmd_expr) | |
3341 { | |
3342 if (math::isnan (base) | |
3343 || math::isnan (increment) | |
3344 || math::isnan (limit)) | |
3345 return octave_value (numeric_limits<T>::NaN ()); | |
3346 | |
3347 if (increment == 0 | |
3348 || (increment > 0 && base > limit) | |
3349 || (increment < 0 && base < limit)) | |
3350 return octave_value (Array<T> (dim_vector (1, 0))); | |
3351 | |
3352 // At this point, we know that the base and limit values are | |
3353 // consistent with the sign of the increment (not an empty range). | |
3354 | |
3355 range<T> r (base, increment, limit); | |
3356 | |
3357 if (! is_for_cmd_expr && ! r.is_storable ()) | |
3358 error ("range with infinite number of elements cannot be stored"); | |
3359 | |
3360 return octave_value (r, is_for_cmd_expr); | |
3361 } | |
3362 | |
3363 template <typename T, | |
3364 typename std::enable_if<std::is_same<T, float>::value, | |
3365 bool>::type = true> | |
3366 octave_value | |
3367 make_float_range (T base, T increment, T limit, bool is_for_cmd_expr) | |
3368 { | |
3369 if (math::isnan (base) | |
3370 || math::isnan (increment) | |
3371 || math::isnan (limit)) | |
3372 return octave_value (numeric_limits<T>::NaN ()); | |
3373 | |
3374 if (increment == 0 | |
3375 || (increment > 0 && base > limit) | |
3376 || (increment < 0 && base < limit)) | |
3377 return octave_value (Array<T> (dim_vector (1, 0))); | |
3378 | |
3379 // At this point, we know that the base and limit values are | |
3380 // consistent with the sign of the increment (not an empty range). | |
3381 | |
3382 range<T> r (base, increment, limit); | |
3383 | |
3384 if (! is_for_cmd_expr && ! r.is_storable ()) | |
3385 error ("range with infinite number of elements cannot be stored"); | |
3386 | |
3387 return octave_value (r.array_value ()); | |
3388 } | |
3389 | |
3390 template <typename T, | |
3391 typename std::enable_if<(std::is_same<T, octave_int8>::value | |
3392 || std::is_same<T, octave_uint8>::value | |
3393 || std::is_same<T, octave_int16>::value | |
3394 || std::is_same<T, octave_uint16>::value | |
3395 || std::is_same<T, octave_int32>::value | |
3396 || std::is_same<T, octave_uint32>::value | |
3397 || std::is_same<T, octave_int64>::value | |
3398 || std::is_same<T, octave_uint64>::value), | |
3399 bool>::type = true> | |
3400 octave_value | |
3401 make_int_range (const octave_value& base, const octave_value& increment, | |
3402 const octave_value& limit) | |
3403 { | |
3404 if (base.isempty () || increment.isempty () || limit.isempty ()) | |
3405 return octave_value (Array<T> (dim_vector (1, 0))); | |
3406 | |
3407 check_colon_operand<T> (base, "lower bound"); | |
3408 check_colon_operand<T> (limit, "upper bound"); | |
3409 | |
3410 typename T::val_type base_val = octave_value_extract<T> (base).value (); | |
3411 typename T::val_type limit_val = octave_value_extract<T> (limit).value (); | |
3412 | |
3413 if (increment.is_double_type ()) | |
3414 { | |
3415 double increment_val = increment.double_value (); | |
3416 | |
3417 return make_int_range (base_val, increment_val, limit_val); | |
3418 } | |
3419 | |
3420 check_colon_operand<T> (increment, "increment"); | |
3421 | |
3422 typename T::val_type increment_val | |
3423 = octave_value_extract<T> (increment).value (); | |
3424 | |
3425 return make_int_range (base_val, increment_val, limit_val); | |
3426 } | |
3427 | |
3428 template <typename T, | |
3429 typename std::enable_if<std::is_floating_point<T>::value, | |
3430 bool>::type = true> | |
3431 octave_value | |
3432 make_float_range (const octave_value& base, const octave_value& increment, | |
3433 const octave_value& limit, bool is_for_cmd_expr) | |
3434 { | |
3435 if (base.isempty () || increment.isempty () || limit.isempty ()) | |
3436 return octave_value (Array<T> (dim_vector (1, 0))); | |
3437 | |
3438 T base_val = octave_value_extract<T> (base); | |
3439 T increment_val = octave_value_extract<T> (increment); | |
3440 T limit_val = octave_value_extract<T> (limit); | |
3441 | |
3442 return make_float_range (base_val, increment_val, limit_val, | |
3443 is_for_cmd_expr); | |
3444 } | |
3445 | |
3446 | |
3447 octave_value | |
3448 make_char_range (const octave_value& base, const octave_value& increment, | |
3449 const octave_value& limit) | |
3450 { | |
3451 octave_value retval; | |
3452 | |
3453 bool dq_str = (base.is_dq_string () || increment.is_dq_string () | |
3454 || limit.is_dq_string ()); | |
3455 | |
3456 char type = dq_str ? '"' : '\''; | |
3457 | |
3458 if (base.isempty () || increment.isempty () || limit.isempty ()) | |
3459 retval = octave_value ("", type); | |
3460 else | |
3461 { | |
3462 Matrix mtx_base = base.matrix_value (true); | |
3463 Matrix mtx_increment = increment.matrix_value (true); | |
3464 Matrix mtx_limit = limit.matrix_value (true); | |
3465 | |
3466 range<double> tmp (mtx_base(0), mtx_increment(0), mtx_limit(0)); | |
3467 | |
3468 retval = octave_value (tmp); | |
3469 } | |
3470 | |
3471 return retval.convert_to_str (false, true, type); | |
3472 } | |
3473 | |
3474 octave_value | |
3475 colon_op (const octave_value& base, const octave_value& increment_arg, | |
3476 const octave_value& limit, bool is_for_cmd_expr) | |
3477 { | |
3478 if (base.isobject () || increment_arg.isobject () || limit.isobject ()) | |
3479 { | |
3480 octave_value_list tmp1; | |
3481 | |
3482 if (increment_arg.is_defined ()) | |
3483 { | |
3484 tmp1(2) = limit; | |
3485 tmp1(1) = increment_arg; | |
3486 tmp1(0) = base; | |
3487 } | |
3488 else | |
3489 { | |
3490 tmp1(1) = limit; | |
3491 tmp1(0) = base; | |
3492 } | |
3493 | |
3494 interpreter& interp = __get_interpreter__ (); | |
3495 | |
3496 symbol_table& symtab = interp.get_symbol_table (); | |
3497 | |
3498 octave_value fcn = symtab.find_function ("colon", tmp1); | |
3499 | |
3500 if (fcn.is_defined ()) | |
3501 { | |
3502 octave_value_list tmp2 = interp.feval (fcn, tmp1, 1); | |
3503 | |
3504 return tmp2(0); | |
3505 } | |
3506 } | |
3507 | |
3508 octave_value increment | |
3509 = increment_arg.is_defined () ? increment_arg : octave_value (1.0); | |
3510 | |
3511 if (base.numel () > 1 || limit.numel () > 1 || increment.numel () > 1) | |
3512 warning_with_id ("Octave:colon-nonscalar-argument", | |
3513 "colon arguments should be scalars"); | |
3514 | |
3515 if (base.iscomplex () || limit.iscomplex () || increment.iscomplex ()) | |
3516 warning_with_id ("Octave:colon-complex-argument", | |
3517 "imaginary part of complex colon arguments is ignored"); | |
3518 | |
3519 // FIXME: is there a better way to do this job, maybe using type traits? | |
3520 | |
3521 builtin_type_t type_id = get_colon_op_type (base, increment, limit); | |
3522 | |
3523 // For compatibility with Matlab, don't allow the range used in | |
3524 // a FOR loop expression to be converted to a Matrix. | |
3525 | |
3526 // For now, these functions create arrays instead of range<T> for | |
3527 // all types except double. | |
3528 | |
3529 switch (type_id) | |
3530 { | |
3531 case btyp_double: | |
3532 case btyp_complex: | |
3533 return make_float_range<double> (base, increment, limit, is_for_cmd_expr); | |
3534 | |
3535 case btyp_float: | |
3536 case btyp_float_complex: | |
3537 return make_float_range<float> (base, increment, limit, is_for_cmd_expr); | |
3538 | |
3539 case btyp_int8: | |
3540 return make_int_range<octave_int8> (base, increment, limit); | |
3541 | |
3542 case btyp_int16: | |
3543 return make_int_range<octave_int16> (base, increment, limit); | |
3544 | |
3545 case btyp_int32: | |
3546 return make_int_range<octave_int32> (base, increment, limit); | |
3547 | |
3548 case btyp_int64: | |
3549 return make_int_range<octave_int64> (base, increment, limit); | |
3550 | |
3551 case btyp_uint8: | |
3552 return make_int_range<octave_uint8> (base, increment, limit); | |
3553 | |
3554 case btyp_uint16: | |
3555 return make_int_range<octave_uint16> (base, increment, limit); | |
3556 | |
3557 case btyp_uint32: | |
3558 return make_int_range<octave_uint32> (base, increment, limit); | |
3559 | |
3560 case btyp_uint64: | |
3561 return make_int_range<octave_uint64> (base, increment, limit); | |
3562 | |
3563 case btyp_char: | |
3564 return make_char_range (base, increment, limit); | |
3565 | |
3566 case btyp_unknown: | |
3567 error ("incompatible types found in range expression"); | |
3568 | |
3569 default: | |
3570 error ("invalid types found in range expression"); | |
3571 } | |
3572 | |
3573 return octave_value (); | |
3574 } | |
3575 | |
3576 OCTAVE_NORETURN static void | |
3577 err_unary_op_conv (const std::string& on) | |
3578 { | |
3579 error ("type conversion failed for unary operator '%s'", on.c_str ()); | |
3580 } | |
3581 | |
3582 octave_value | |
3583 unary_op (type_info& ti, octave_value::unary_op op, | |
3584 const octave_value& v) | |
3585 { | |
3586 octave_value retval; | |
3587 | |
3588 int t = v.type_id (); | |
3589 | |
3590 if (t == octave_class::static_type_id () | |
3591 || t == octave_classdef::static_type_id ()) | |
3592 { | |
3593 type_info::unary_class_op_fcn f = ti.lookup_unary_class_op (op); | |
3594 | |
3595 if (! f) | |
3596 err_unary_op (octave_value::unary_op_as_string (op), v.class_name ()); | |
3597 | |
3598 retval = f (v); | |
3599 } | |
3600 else | |
3601 { | |
3602 // FIXME: we need to handle overloading operators for built-in | |
3603 // classes (double, char, int8, etc.) | |
3604 | |
3605 type_info::unary_op_fcn f = ti.lookup_unary_op (op, t); | |
3606 | |
3607 if (f) | |
3608 retval = f (v.get_rep ()); | |
3609 else | |
3610 { | |
3611 octave_value tv; | |
3612 octave_base_value::type_conv_fcn cf | |
3613 = v.numeric_conversion_function (); | |
3614 | |
3615 if (! cf) | |
3616 err_unary_op (octave_value::unary_op_as_string (op), | |
3617 v.type_name ()); | |
3618 | |
3619 octave_base_value *tmp = cf (v.get_rep ()); | |
3620 | |
3621 if (! tmp) | |
3622 err_unary_op_conv (octave_value::unary_op_as_string (op)); | |
3623 | |
3624 tv = octave_value (tmp); | |
3625 retval = unary_op (op, tv); | |
3626 } | |
3627 } | |
3628 | |
3629 return retval; | |
3630 } | |
3631 | |
3632 octave_value | |
3633 unary_op (octave_value::unary_op op, const octave_value& v) | |
3634 { | |
3635 type_info& ti = __get_type_info__ (); | |
3636 | |
3637 return unary_op (ti, op, v); | |
3638 } | |
3635 | 3639 |
3636 OCTAVE_END_NAMESPACE(octave) | 3640 OCTAVE_END_NAMESPACE(octave) |
3637 | 3641 |
3638 void | 3642 void |
3639 install_types (octave::type_info& ti) | 3643 install_types (octave::type_info& ti) |
3742 static void | 3746 static void |
3743 decode_subscripts (const char *name, const octave_value& arg, | 3747 decode_subscripts (const char *name, const octave_value& arg, |
3744 std::string& type_string, | 3748 std::string& type_string, |
3745 std::list<octave_value_list>& idx) | 3749 std::list<octave_value_list>& idx) |
3746 { | 3750 { |
3747 const octave_map m = arg.xmap_value ("%s: second argument must be a structure with fields 'type' and 'subs'", name); | 3751 const octave_map m = |
3752 arg.xmap_value ("%s: second argument must be a structure with fields 'type' and 'subs'", name); | |
3748 | 3753 |
3749 if (m.nfields () != 2 || ! m.contains ("type") || ! m.contains ("subs")) | 3754 if (m.nfields () != 2 || ! m.contains ("type") || ! m.contains ("subs")) |
3750 error ("%s: second argument must be a structure with fields 'type' and 'subs'", | 3755 error ("%s: second argument must be a structure with fields 'type' and 'subs'", |
3751 name); | 3756 name); |
3752 | 3757 |