Mercurial > octave
comparison libinterp/octave-value/ov.cc @ 28633:c897ec8fb5d1
refactor octave_value colon_op function
* ov.h, ov.cc (get_colon_op_type): New functions.
(make_range): New template function.
(make_range<char>): New specialization.
(colon_op): Update to use new make_range template.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Fri, 31 Jul 2020 13:18:01 -0400 |
parents | 70cdf8de553d |
children | 98192ec1621f |
comparison
equal
deleted
inserted
replaced
28632:6aa0808d2ed6 | 28633:c897ec8fb5d1 |
---|---|
2818 type_info& ti = __get_type_info__ ("cat_op"); | 2818 type_info& ti = __get_type_info__ ("cat_op"); |
2819 | 2819 |
2820 return cat_op (ti, v1, v2, ra_idx); | 2820 return cat_op (ti, v1, v2, ra_idx); |
2821 } | 2821 } |
2822 | 2822 |
2823 // Unless the colon operator is used with a class or classdef object, | |
2824 // then all arguments must be the same type or mixed with double | |
2825 // values. | |
2826 | |
2827 static builtin_type_t | |
2828 get_colon_op_type (builtin_type_t op1_type, builtin_type_t op2_type) | |
2829 { | |
2830 if (op1_type == op2_type) | |
2831 return op1_type; | |
2832 | |
2833 if (op1_type == btyp_double) | |
2834 return op2_type; | |
2835 | |
2836 if (op2_type == btyp_double) | |
2837 return op1_type; | |
2838 | |
2839 return btyp_unknown; | |
2840 } | |
2841 | |
2842 static builtin_type_t | |
2843 get_colon_op_type (const octave_value& base, const octave_value& increment, | |
2844 const octave_value& limit) | |
2845 { | |
2846 builtin_type_t typ | |
2847 = get_colon_op_type (base.builtin_type (), increment.builtin_type ()); | |
2848 | |
2849 if (typ == btyp_unknown) | |
2850 return typ; | |
2851 | |
2852 return get_colon_op_type (typ, limit.builtin_type ()); | |
2853 } | |
2854 | |
2855 template <typename T> | |
2823 octave_value | 2856 octave_value |
2824 colon_op (const octave_value& base, const octave_value& increment, | 2857 make_range (const octave_value& base, const octave_value& increment, |
2858 const octave_value& limit, bool for_cmd_expr) | |
2859 { | |
2860 if (base.isempty () || increment.isempty () || limit.isempty ()) | |
2861 return octave_value (Range (), for_cmd_expr); | |
2862 | |
2863 T b = octave_value_extract<T> (base); | |
2864 T i = octave_value_extract<T> (increment); | |
2865 T l = octave_value_extract<T> (limit); | |
2866 | |
2867 // FIXME: ultimately, we will eliminate these casts and create range | |
2868 // objects that properly correspond to the type T. | |
2869 | |
2870 double db = static_cast<double> (b); | |
2871 double di = static_cast<double> (i); | |
2872 double dl = static_cast<double> (l); | |
2873 | |
2874 return octave_value (Range (db, dl, di), for_cmd_expr); | |
2875 } | |
2876 | |
2877 template <> | |
2878 octave_value | |
2879 make_range<char> (const octave_value& base, const octave_value& increment, | |
2880 const octave_value& limit, bool for_cmd_expr) | |
2881 { | |
2882 octave_value retval; | |
2883 | |
2884 if (base.isempty () || increment.isempty () || limit.isempty ()) | |
2885 retval = octave_value (Range (), for_cmd_expr); | |
2886 else | |
2887 { | |
2888 Matrix mtx_base = base.matrix_value (true); | |
2889 Matrix mtx_increment = increment.matrix_value (true); | |
2890 Matrix mtx_limit = limit.matrix_value (true); | |
2891 | |
2892 double b = mtx_base(0); | |
2893 double i = mtx_increment(0); | |
2894 double l = mtx_limit(0); | |
2895 | |
2896 retval = octave_value (Range (b, l, i), for_cmd_expr); | |
2897 } | |
2898 | |
2899 bool dq_str = (base.is_dq_string () || increment.is_dq_string () | |
2900 || limit.is_dq_string ()); | |
2901 | |
2902 return retval.convert_to_str (false, true, dq_str ? '"' : '\''); | |
2903 } | |
2904 | |
2905 octave_value | |
2906 colon_op (const octave_value& base, const octave_value& increment_arg, | |
2825 const octave_value& limit, bool is_for_cmd_expr) | 2907 const octave_value& limit, bool is_for_cmd_expr) |
2826 { | 2908 { |
2827 octave_value retval; | 2909 if (base.isobject () || increment_arg.isobject () || limit.isobject ()) |
2828 | |
2829 if (base.isobject () || increment.isobject () || limit.isobject ()) | |
2830 { | 2910 { |
2831 octave_value_list tmp1; | 2911 octave_value_list tmp1; |
2832 | 2912 |
2833 if (increment.is_defined ()) | 2913 if (increment_arg.is_defined ()) |
2834 { | 2914 { |
2835 tmp1(2) = limit; | 2915 tmp1(2) = limit; |
2836 tmp1(1) = increment; | 2916 tmp1(1) = increment_arg; |
2837 tmp1(0) = base; | 2917 tmp1(0) = base; |
2838 } | 2918 } |
2839 else | 2919 else |
2840 { | 2920 { |
2841 tmp1(1) = limit; | 2921 tmp1(1) = limit; |
2854 | 2934 |
2855 return tmp2 (0); | 2935 return tmp2 (0); |
2856 } | 2936 } |
2857 } | 2937 } |
2858 | 2938 |
2859 bool result_is_str = (base.is_string () && limit.is_string ()); | 2939 octave_value increment |
2860 bool dq_str = (base.is_dq_string () || limit.is_dq_string ()); | 2940 = increment_arg.is_defined () ? increment_arg : octave_value (1.0); |
2861 | 2941 |
2862 if (base.numel () > 1 || limit.numel () > 1 | 2942 if (base.numel () > 1 || limit.numel () > 1 || increment.numel () > 1) |
2863 || (increment.is_defined () && increment.numel () > 1)) | |
2864 warning_with_id ("Octave:colon-nonscalar-argument", | 2943 warning_with_id ("Octave:colon-nonscalar-argument", |
2865 "colon arguments should be scalars"); | 2944 "colon arguments should be scalars"); |
2866 | 2945 |
2867 if (base.iscomplex () || limit.iscomplex () | 2946 if (base.iscomplex () || limit.iscomplex () || increment.iscomplex ()) |
2868 || (increment.is_defined () && increment.iscomplex ())) | |
2869 warning_with_id ("Octave:colon-complex-argument", | 2947 warning_with_id ("Octave:colon-complex-argument", |
2870 "imaginary part of complex colon arguments is ignored"); | 2948 "imaginary part of complex colon arguments is ignored"); |
2871 | 2949 |
2872 Matrix m_base, m_limit, m_increment; | 2950 // FIXME: is there a better way to do this job, maybe using type traits? |
2873 | 2951 |
2874 try | 2952 builtin_type_t type_id = get_colon_op_type (base, increment, limit); |
2953 | |
2954 // For compatibility with Matlab, don't allow the range used in | |
2955 // a FOR loop expression to be converted to a Matrix. | |
2956 | |
2957 switch (type_id) | |
2875 { | 2958 { |
2876 m_base = base.matrix_value (true); | 2959 case btyp_double: |
2960 case btyp_complex: | |
2961 return make_range<double> (base, increment, limit, is_for_cmd_expr); | |
2962 | |
2963 case btyp_float: | |
2964 case btyp_float_complex: | |
2965 return make_range<float> (base, increment, limit, is_for_cmd_expr); | |
2966 | |
2967 case btyp_int8: | |
2968 return make_range<octave_int8> (base, increment, limit, is_for_cmd_expr); | |
2969 | |
2970 case btyp_int16: | |
2971 return make_range<octave_int16> (base, increment, limit, is_for_cmd_expr); | |
2972 | |
2973 case btyp_int32: | |
2974 return make_range<octave_int32> (base, increment, limit, is_for_cmd_expr); | |
2975 | |
2976 case btyp_int64: | |
2977 return make_range<octave_int64> (base, increment, limit, is_for_cmd_expr); | |
2978 | |
2979 case btyp_uint8: | |
2980 return make_range<octave_uint8> (base, increment, limit, is_for_cmd_expr); | |
2981 | |
2982 case btyp_uint16: | |
2983 return make_range<octave_uint16> (base, increment, limit, is_for_cmd_expr); | |
2984 | |
2985 case btyp_uint32: | |
2986 return make_range<octave_uint32> (base, increment, limit, is_for_cmd_expr); | |
2987 | |
2988 case btyp_uint64: | |
2989 return make_range<octave_uint64> (base, increment, limit, is_for_cmd_expr); | |
2990 | |
2991 case btyp_char: | |
2992 return make_range<char> (base, increment, limit, is_for_cmd_expr); | |
2993 | |
2994 default: | |
2995 error ("invalid types found in range expression"); | |
2877 } | 2996 } |
2878 catch (execution_exception& e) | 2997 |
2879 { | 2998 return octave_value (); |
2880 error (e, "invalid base value in colon expression"); | |
2881 } | |
2882 | |
2883 try | |
2884 { | |
2885 m_limit = limit.matrix_value (true); | |
2886 } | |
2887 catch (execution_exception& e) | |
2888 { | |
2889 error (e, "invalid limit value in colon expression"); | |
2890 } | |
2891 | |
2892 try | |
2893 { | |
2894 m_increment = (increment.is_defined () | |
2895 ? increment.matrix_value (true) | |
2896 : Matrix (1, 1, 1.0)); | |
2897 } | |
2898 catch (execution_exception& e) | |
2899 { | |
2900 error (e, "invalid increment value in colon expression"); | |
2901 } | |
2902 | |
2903 bool base_empty = m_base.isempty (); | |
2904 bool limit_empty = m_limit.isempty (); | |
2905 bool increment_empty = m_increment.isempty (); | |
2906 | |
2907 if (base_empty || limit_empty || increment_empty) | |
2908 retval = Range (); | |
2909 else | |
2910 { | |
2911 Range r (m_base(0), m_limit(0), m_increment(0)); | |
2912 | |
2913 // For compatibility with Matlab, don't allow the range used in | |
2914 // a FOR loop expression to be converted to a Matrix. | |
2915 | |
2916 retval = octave_value (r, is_for_cmd_expr); | |
2917 | |
2918 if (result_is_str) | |
2919 retval = (retval.convert_to_str (false, true, dq_str ? '"' : '\'')); | |
2920 } | |
2921 | |
2922 return retval; | |
2923 } | 2999 } |
2924 | 3000 |
2925 OCTAVE_NORETURN static void | 3001 OCTAVE_NORETURN static void |
2926 err_unary_op_conv (const std::string& on) | 3002 err_unary_op_conv (const std::string& on) |
2927 { | 3003 { |