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