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 {