/* @overload rindex(pattern, offset = -1) * * Returns the maximal index of the receiver where PATTERN matches, equal to * or less than _i_, where _i_ = OFFSET if OFFSET ≥ 0, _i_ = {#length} - * abs(OFFSET) otherwise, or nil if there is no match. * * If PATTERN is a Regexp, the Regexp special variables `$&`, `$'`, * <code>$\`</code>, `$1`, `$2`, …, `$`_n_ are updated accordingly. * * If PATTERN responds to `#to_str`, the matching is performed by a byte * comparison. * * @param [Regexp, #to_str] pattern * @param [#to_int] offset * @return [Integer, nil] * @see #index */ VALUE rb_u_string_rindex_m(int argc, VALUE *argv, VALUE self) { const struct rb_u_string *string = RVAL2USTRING(self); VALUE sub, rboffset; long offset; if (rb_scan_args(argc, argv, "11", &sub, &rboffset) == 2) offset = NUM2LONG(rboffset); else /* TODO: Why not simply use -1? Benchmark which is faster. */ offset = u_n_chars_n(USTRING_STR(string), USTRING_LENGTH(string)); const char *begin = rb_u_string_begin_from_offset(string, offset); const char *end = USTRING_END(string); if (begin == NULL) { if (offset <= 0) { if (TYPE(sub) == T_REGEXP) rb_backref_set(Qnil); return Qnil; } begin = end; /* TODO: this converting back and forward can be optimized away * if rb_u_string_index_regexp() and rb_u_string_rindex() were split up * into two additional functions, adding * rb_u_string_index_regexp_pointer() and rb_u_string_rindex_pointer(), * so that one can pass a pointer to start at immediately * instead of an offset that gets calculated into a pointer. */ offset = u_n_chars_n(USTRING_STR(string), USTRING_LENGTH(string)); } switch (TYPE(sub)) { case T_REGEXP: /* TODO: What’s this first test for, exactly? */ if (RREGEXP(sub)->ptr == NULL || RREGEXP_SRC_LEN(sub) > 0) offset = rb_u_string_index_regexp(self, begin, sub, true); break; default: { VALUE tmp = rb_check_string_type(sub); if (NIL_P(tmp)) rb_u_raise(rb_eTypeError, "type mismatch: %s given", rb_obj_classname(sub)); sub = tmp; } /* fall through */ case T_STRING: offset = rb_u_string_rindex(self, sub, offset); break; } if (offset < 0) return Qnil; return LONG2NUM(offset); }
/* * call-seq: * str.to_c -> complex * * Returns a complex which denotes the string form. The parser * ignores leading whitespaces and trailing garbage. Any digit * sequences can be separated by an underscore. Returns zero for null * or garbage string. * * For example: * * '9'.to_c #=> (9+0i) * '2.5'.to_c #=> (2.5+0i) * '2.5/1'.to_c #=> ((5/2)+0i) * '-3/2'.to_c #=> ((-3/2)+0i) * '-i'.to_c #=> (0-1i) * '45i'.to_c #=> (0+45i) * '3-4i'.to_c #=> (3-4i) * '-4e2-4e-2i'.to_c #=> (-400.0-0.04i) * '-0.0-0.0i'.to_c #=> (-0.0-0.0i) * '1/2+3/4i'.to_c #=> ((1/2)+(3/4)*i) * 'ruby'.to_c #=> (0+0i) */ static VALUE string_to_c(VALUE self) { VALUE s, a, backref; backref = rb_backref_get(); rb_match_busy(backref); s = f_gsub(self, underscores_pat, an_underscore); a = string_to_c_internal(s); rb_backref_set(backref); if (!NIL_P(RARRAY_PTR(a)[0])) return RARRAY_PTR(a)[0]; return rb_complex_new1(INT2FIX(0)); }
/* @overload index(pattern, offset = 0) * * Returns the minimal index of the receiver where PATTERN matches, equal to or * greater than _i_, where _i_ = OFFSET if OFFSET ≥ 0, _i_ = {#length} - * abs(OFFSET) otherwise, or nil if there is no match. * * If PATTERN is a Regexp, the Regexp special variables `$&`, `$'`, * <code>$\`</code>, `$1`, `$2`, …, `$`_n_ are updated accordingly. * * If PATTERN responds to #to_str, the matching is performed by byte * comparison. * * @param [Regexp, #to_str] pattern * @param [#to_int] offset * @return [Integer, nil] * @see #rindex */ VALUE rb_u_string_index_m(int argc, VALUE *argv, VALUE self) { VALUE sub, rboffset; long offset = 0; if (rb_scan_args(argc, argv, "11", &sub, &rboffset) == 2) offset = NUM2LONG(rboffset); const struct rb_u_string *string = RVAL2USTRING(self); const char *begin = rb_u_string_begin_from_offset(string, offset); if (begin == NULL) { if (TYPE(sub) == T_REGEXP) rb_backref_set(Qnil); return Qnil; } switch (TYPE(sub)) { case T_REGEXP: offset = rb_u_string_index_regexp(self, begin, sub, false); break; default: { VALUE tmp = rb_check_string_type(sub); if (NIL_P(tmp)) rb_u_raise(rb_eTypeError, "type mismatch: %s given", rb_obj_classname(sub)); sub = tmp; } /* fall through */ case T_STRING: offset = rb_u_string_index(self, sub, offset); break; } if (offset < 0) return Qnil; return LONG2NUM(offset); }
static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass) { VALUE a1, a2, backref; rb_scan_args(argc, argv, "11", &a1, &a2); if (NIL_P(a1) || (argc == 2 && NIL_P(a2))) rb_raise(rb_eTypeError, "can't convert nil into Complex"); backref = rb_backref_get(); rb_match_busy(backref); if (RB_TYPE_P(a1, T_STRING)) { a1 = string_to_c_strict(a1); } if (RB_TYPE_P(a2, T_STRING)) { a2 = string_to_c_strict(a2); } rb_backref_set(backref); if (RB_TYPE_P(a1, T_COMPLEX)) { { get_dat1(a1); if (k_exact_zero_p(dat->imag)) a1 = dat->real; } } if (RB_TYPE_P(a2, T_COMPLEX)) { { get_dat1(a2); if (k_exact_zero_p(dat->imag)) a2 = dat->real; } } if (RB_TYPE_P(a1, T_COMPLEX)) { if (argc == 1 || (k_exact_zero_p(a2))) return a1; } if (argc == 1) { if (k_numeric_p(a1) && !f_real_p(a1)) return a1; /* should raise exception for consistency */ if (!k_numeric_p(a1)) return rb_convert_type(a1, T_COMPLEX, "Complex", "to_c"); } else { if ((k_numeric_p(a1) && k_numeric_p(a2)) && (!f_real_p(a1) || !f_real_p(a2))) return f_add(a1, f_mul(a2, f_complex_new_bang2(rb_cComplex, ZERO, ONE))); } { VALUE argv2[2]; argv2[0] = a1; argv2[1] = a2; return nucomp_s_new(argc, argv2, klass); } }
static VALUE nurat_s_convert(VALUE klass, SEL sel, int argc, VALUE *argv) { VALUE a1, a2, backref; rb_scan_args(argc, argv, "11", &a1, &a2); if (NIL_P(a1) || (argc == 2 && NIL_P(a2))) rb_raise(rb_eTypeError, "can't convert nil into Rational"); switch (TYPE(a1)) { case T_COMPLEX: if (k_exact_zero_p(RCOMPLEX(a1)->imag)) a1 = RCOMPLEX(a1)->real; } switch (TYPE(a2)) { case T_COMPLEX: if (k_exact_zero_p(RCOMPLEX(a2)->imag)) a2 = RCOMPLEX(a2)->real; } backref = rb_backref_get(); rb_match_busy(backref); switch (TYPE(a1)) { case T_FIXNUM: case T_BIGNUM: break; case T_FLOAT: a1 = f_to_r(a1); break; case T_STRING: a1 = string_to_r_strict(a1); break; } switch (TYPE(a2)) { case T_FIXNUM: case T_BIGNUM: break; case T_FLOAT: a2 = f_to_r(a2); break; case T_STRING: a2 = string_to_r_strict(a2); break; } rb_backref_set(backref); switch (TYPE(a1)) { case T_RATIONAL: if (argc == 1 || (k_exact_one_p(a2))) return a1; } if (argc == 1) { if (!(k_numeric_p(a1) && k_integer_p(a1))) return rb_convert_type(a1, T_RATIONAL, "Rational", "to_r"); } else { if ((k_numeric_p(a1) && k_numeric_p(a2)) && (!f_integer_p(a1) || !f_integer_p(a2))) return f_div(a1, a2); } { VALUE argv2[2]; argv2[0] = a1; argv2[1] = a2; return nurat_s_new(argc, argv2, klass); } }
static VALUE nurat_s_convert(int argc, VALUE *argv, VALUE klass) { VALUE a1, a2, backref; rb_scan_args(argc, argv, "11", &a1, &a2); switch (TYPE(a1)) { case T_COMPLEX: if (k_exact_p(RCOMPLEX(a1)->imag) && f_zero_p(RCOMPLEX(a1)->imag)) a1 = RCOMPLEX(a1)->real; } switch (TYPE(a2)) { case T_COMPLEX: if (k_exact_p(RCOMPLEX(a2)->imag) && f_zero_p(RCOMPLEX(a2)->imag)) a2 = RCOMPLEX(a2)->real; } backref = rb_backref_get(); rb_match_busy(backref); switch (TYPE(a1)) { case T_FIXNUM: case T_BIGNUM: break; case T_FLOAT: a1 = f_to_r(a1); break; case T_STRING: a1 = string_to_r_strict(a1); break; } switch (TYPE(a2)) { case T_FIXNUM: case T_BIGNUM: break; case T_FLOAT: a2 = f_to_r(a2); break; case T_STRING: a2 = string_to_r_strict(a2); break; } rb_backref_set(backref); switch (TYPE(a1)) { case T_RATIONAL: if (argc == 1 || (k_exact_p(a2) && f_one_p(a2))) return a1; } if (argc == 1) { if (k_numeric_p(a1) && !f_integer_p(a1)) return a1; } else { if ((k_numeric_p(a1) && k_numeric_p(a2)) && (!f_integer_p(a1) || !f_integer_p(a2))) return f_div(a1, a2); } { VALUE argv2[2]; argv2[0] = a1; argv2[1] = a2; return nurat_s_new(argc, argv2, klass); } }
static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass) { VALUE a1, a2, backref; rb_scan_args(argc, argv, "11", &a1, &a2); backref = rb_backref_get(); rb_match_busy(backref); switch (TYPE(a1)) { case T_FIXNUM: case T_BIGNUM: case T_FLOAT: break; case T_STRING: a1 = string_to_c_strict(a1); break; } switch (TYPE(a2)) { case T_FIXNUM: case T_BIGNUM: case T_FLOAT: break; case T_STRING: a2 = string_to_c_strict(a2); break; } rb_backref_set(backref); switch (TYPE(a1)) { case T_COMPLEX: { get_dat1(a1); if (k_exact_p(dat->imag) && f_zero_p(dat->imag)) a1 = dat->real; } } switch (TYPE(a2)) { case T_COMPLEX: { get_dat1(a2); if (k_exact_p(dat->imag) && f_zero_p(dat->imag)) a2 = dat->real; } } switch (TYPE(a1)) { case T_COMPLEX: if (argc == 1 || (k_exact_p(a2) && f_zero_p(a2))) return a1; } if (argc == 1) { if (k_numeric_p(a1) && !f_real_p(a1)) return a1; } else { if ((k_numeric_p(a1) && k_numeric_p(a2)) && (!f_real_p(a1) || !f_real_p(a2))) return f_add(a1, f_mul(a2, f_complex_new_bang2(rb_cComplex, ZERO, ONE))); } { VALUE argv2[2]; argv2[0] = a1; argv2[1] = a2; return nucomp_s_new(argc, argv2, klass); } }