static VALUE range_to_s(VALUE range) { VALUE str, str2; str = rb_obj_as_string(RANGE_BEG(range)); str2 = rb_obj_as_string(RANGE_END(range)); str = rb_str_dup(str); rb_str_cat(str, "...", EXCL(range) ? 3 : 2); rb_str_append(str, str2); OBJ_INFECT(str, str2); return str; }
static VALUE range_dumper(VALUE range) { VALUE v; NEWOBJ(m, struct RObject); OBJSETUP(m, rb_cObject, T_OBJECT); v = (VALUE)m; rb_ivar_set(v, id_excl, RANGE_EXCL(range)); rb_ivar_set(v, id_beg, RANGE_BEG(range)); rb_ivar_set(v, id_end, RANGE_END(range)); return v; }
static VALUE range_first(int argc, VALUE *argv, VALUE range) { VALUE n, ary[2]; if (argc == 0) return RANGE_BEG(range); rb_scan_args(argc, argv, "1", &n); ary[0] = n; ary[1] = rb_ary_new2(NUM2LONG(n)); rb_block_call(range, rb_intern("each"), 0, 0, first_i, (VALUE)ary); return ary[1]; }
static VALUE range_each(VALUE range, SEL sel) { VALUE beg, end; RETURN_ENUMERATOR(range, 0, 0); beg = RANGE_BEG(range); end = RANGE_END(range); if (FIXNUM_P(beg) && FIXNUM_P(end)) { /* fixnums are special */ long lim = FIX2LONG(end); long i; if (!EXCL(range)) lim += 1; for (i = FIX2LONG(beg); i < lim; i++) { rb_yield(LONG2FIX(i)); RETURN_IF_BROKEN(); } } else if (SYMBOL_P(beg) && SYMBOL_P(end)) { /* symbols are special */ VALUE args[2]; args[0] = rb_sym_to_s(end); args[1] = EXCL(range) ? Qtrue : Qfalse; rb_objc_block_call(rb_sym_to_s(beg), selUpto, 2, args, sym_each_i, 0); } else { VALUE tmp = rb_check_string_type(beg); if (!NIL_P(tmp)) { VALUE args[2]; args[0] = end; args[1] = EXCL(range) ? Qtrue : Qfalse; rb_objc_block_call(beg, selUpto, 2, args, rb_yield, 0); } else { if (!discrete_object_p(beg)) { rb_raise(rb_eTypeError, "can't iterate from %s", rb_obj_classname(beg)); } range_each_func(range, each_i, NULL); } } return range; }
static VALUE range_include(VALUE range, SEL sel, VALUE val) { VALUE beg = RANGE_BEG(range); VALUE end = RANGE_END(range); int nv = FIXNUM_P(beg) || FIXNUM_P(end) || rb_obj_is_kind_of(beg, rb_cNumeric) || rb_obj_is_kind_of(end, rb_cNumeric); if (nv || !NIL_P(rb_check_to_integer(beg, "to_int")) || !NIL_P(rb_check_to_integer(end, "to_int"))) { if (r_le(beg, val)) { if (EXCL(range)) { if (r_lt(val, end)) return Qtrue; } else { if (r_le(val, end)) return Qtrue; } } return Qfalse; } else if (TYPE(beg) == T_STRING && TYPE(end) == T_STRING && RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) { if (NIL_P(val)) return Qfalse; if (TYPE(val) == T_STRING) { if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1) return Qfalse; else { char b = RSTRING_PTR(beg)[0]; char e = RSTRING_PTR(end)[0]; char v = RSTRING_PTR(val)[0]; if (ISASCII(b) && ISASCII(e) && ISASCII(v)) { if (b <= v && v < e) return Qtrue; if (!EXCL(range) && v == e) return Qtrue; return Qfalse; } } } } if (sel == NULL) { sel = sel_registerName("include?:"); } return rb_vm_call_super(range, sel, 1, &val); }
static VALUE range_hash(VALUE range) { st_index_t hash = EXCL(range); VALUE v; hash = rb_hash_start(hash); v = rb_hash(RANGE_BEG(range)); hash = rb_hash_uint(hash, NUM2LONG(v)); v = rb_hash(RANGE_END(range)); hash = rb_hash_uint(hash, NUM2LONG(v)); hash = rb_hash_uint(hash, EXCL(range) << 24); hash = rb_hash_end(hash); return LONG2FIX(hash); }
static VALUE range_min(VALUE range) { if (rb_block_given_p()) { return rb_call_super(0, 0); } else { VALUE b = RANGE_BEG(range); VALUE e = RANGE_END(range); int c = rb_cmpint(rb_funcall(b, id_cmp, 1, e), b, e); if (c > 0 || (c == 0 && EXCL(range))) return Qnil; return b; } }
static VALUE inspect_range(VALUE range, VALUE dummy, int recur) { VALUE str, str2; if (recur) { return rb_str_new2(EXCL(range) ? "(... ... ...)" : "(... .. ...)"); } str = rb_inspect(RANGE_BEG(range)); str2 = rb_inspect(RANGE_END(range)); str = rb_str_dup(str); rb_str_cat(str, "...", EXCL(range) ? 3 : 2); rb_str_append(str, str2); OBJ_INFECT(str, str2); return str; }
static VALUE range_include(VALUE range, VALUE val) { VALUE beg = RANGE_BEG(range); VALUE end = RANGE_END(range); int nv = FIXNUM_P(beg) || FIXNUM_P(end) || rb_obj_is_kind_of(beg, rb_cNumeric) || rb_obj_is_kind_of(end, rb_cNumeric); if (nv || !NIL_P(rb_check_to_integer(beg, "to_int")) || !NIL_P(rb_check_to_integer(end, "to_int"))) { if (r_le(beg, val)) { if (EXCL(range)) { if (r_lt(val, end)) return Qtrue; } else { if (r_le(val, end)) return Qtrue; } } return Qfalse; } else if (RB_TYPE_P(beg, T_STRING) && RB_TYPE_P(end, T_STRING) && RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) { if (NIL_P(val)) return Qfalse; if (RB_TYPE_P(val, T_STRING)) { if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1) return Qfalse; else { char b = RSTRING_PTR(beg)[0]; char e = RSTRING_PTR(end)[0]; char v = RSTRING_PTR(val)[0]; if (ISASCII(b) && ISASCII(e) && ISASCII(v)) { if (b <= v && v < e) return Qtrue; if (!EXCL(range) && v == e) return Qtrue; return Qfalse; } } } } /* TODO: ruby_frame->this_func = rb_intern("include?"); */ return rb_call_super(1, &val); }
static VALUE recursive_hash(VALUE range, VALUE dummy, int recur) { st_index_t hash = EXCL(range); VALUE v; hash = rb_hash_start(hash); if (!recur) { v = rb_hash(RANGE_BEG(range)); hash = rb_hash_uint(hash, NUM2LONG(v)); v = rb_hash(RANGE_END(range)); hash = rb_hash_uint(hash, NUM2LONG(v)); } hash = rb_hash_uint(hash, EXCL(range) << 24); hash = rb_hash_end(hash); return LONG2FIX(hash); }
static VALUE range_cover(VALUE range, SEL sel, VALUE val) { VALUE beg, end; beg = RANGE_BEG(range); end = RANGE_END(range); if (r_le(beg, val)) { if (EXCL(range)) { if (r_lt(val, end)) return Qtrue; } else { if (r_le(val, end)) return Qtrue; } } return Qfalse; }
static VALUE range_min(int argc, VALUE *argv, VALUE range) { if (rb_block_given_p()) { return rb_call_super(argc, argv); } else if (argc != 0) { return range_first(argc, argv, range); } else { VALUE b = RANGE_BEG(range); VALUE e = RANGE_END(range); int c = rb_cmpint(rb_funcall(b, id_cmp, 1, e), b, e); if (c > 0 || (c == 0 && EXCL(range))) return Qnil; return b; } }
static VALUE range_min(VALUE range, SEL sel) { if (rb_block_given_p()) { if (sel == NULL) { sel = sel_registerName("min"); } return rb_vm_call_super(range, sel, 0, NULL); } else { VALUE b = RANGE_BEG(range); VALUE e = RANGE_END(range); int c = rb_cmpint(rb_objs_cmp(b, e), b, e); if (c > 0 || (c == 0 && EXCL(range))) return Qnil; return b; } }
static void range_init(VALUE range, VALUE beg, VALUE end, int exclude_end) { VALUE args[2]; args[0] = beg; args[1] = end; if (!FIXNUM_P(beg) || !FIXNUM_P(end)) { VALUE v; v = rb_rescue(range_check, (VALUE)args, range_failed, 0); if (NIL_P(v)) range_failed(); } SET_EXCL(range, exclude_end); GC_WB(&RANGE_BEG(range), beg); GC_WB(&RANGE_END(range), end); }
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp) { VALUE b, e; int excl; if (rb_obj_is_kind_of(range, rb_cRange)) { b = RANGE_BEG(range); e = RANGE_END(range); excl = EXCL(range); } else { if (!rb_respond_to(range, id_beg)) return (int)Qfalse; if (!rb_respond_to(range, id_end)) return (int)Qfalse; b = rb_funcall(range, id_beg, 0); e = rb_funcall(range, id_end, 0); excl = RTEST(rb_funcall(range, rb_intern("exclude_end?"), 0)); } *begp = b; *endp = e; *exclp = excl; return (int)Qtrue; }
static void range_each_func(VALUE range, rb_block_call_func *func, VALUE arg) { int c; VALUE b = RANGE_BEG(range); VALUE e = RANGE_END(range); VALUE v = b; if (EXCL(range)) { while (r_lt(v, e)) { (*func) (v, arg, 0, 0, 0); v = rb_funcall(v, id_succ, 0, 0); } } else { while ((c = r_le(v, e)) != Qfalse) { (*func) (v, arg, 0, 0, 0); if (c == (int)INT2FIX(0)) break; v = rb_funcall(v, id_succ, 0, 0); } } }
static VALUE range_step_size(VALUE range, VALUE args, VALUE eobj) { VALUE b = RANGE_BEG(range), e = RANGE_END(range); VALUE step = INT2FIX(1); if (args) { step = RARRAY_AREF(args, 0); if (!rb_obj_is_kind_of(step, rb_cNumeric)) { step = rb_to_int(step); } } if (rb_funcall(step, '<', 1, INT2FIX(0))) { rb_raise(rb_eArgError, "step can't be negative"); } else if (!rb_funcall(step, '>', 1, INT2FIX(0))) { rb_raise(rb_eArgError, "step can't be 0"); } if (rb_obj_is_kind_of(b, rb_cNumeric) && rb_obj_is_kind_of(e, rb_cNumeric)) { return ruby_num_interval_step_size(b, e, step, EXCL(range)); } return Qnil; }
static VALUE range_each(VALUE range) { VALUE beg, end; RETURN_ENUMERATOR(range, 0, 0); beg = RANGE_BEG(range); end = RANGE_END(range); if (!rb_respond_to(beg, id_succ)) { rb_raise(rb_eTypeError, "can't iterate from %s", rb_obj_classname(beg)); } if (FIXNUM_P(beg) && FIXNUM_P(end)) { /* fixnums are special */ long lim = FIX2LONG(end); long i; if (!EXCL(range)) lim += 1; for (i = FIX2LONG(beg); i < lim; i++) { rb_yield(LONG2NUM(i)); } } else if (TYPE(beg) == T_STRING) { VALUE args[2]; args[0] = end; args[1] = EXCL(range) ? Qtrue : Qfalse; rb_block_call(beg, rb_intern("upto"), 2, args, rb_yield, 0); } else { range_each_func(range, each_i, beg, end, NULL); } return range; }
static VALUE range_step(int argc, VALUE *argv, VALUE range) { VALUE b, e, step, tmp; RETURN_SIZED_ENUMERATOR(range, argc, argv, range_step_size); b = RANGE_BEG(range); e = RANGE_END(range); if (argc == 0) { step = INT2FIX(1); } else { rb_scan_args(argc, argv, "01", &step); if (!rb_obj_is_kind_of(step, rb_cNumeric)) { step = rb_to_int(step); } if (rb_funcall(step, '<', 1, INT2FIX(0))) { rb_raise(rb_eArgError, "step can't be negative"); } else if (!rb_funcall(step, '>', 1, INT2FIX(0))) { rb_raise(rb_eArgError, "step can't be 0"); } } if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */ long end = FIX2LONG(e); long i, unit = FIX2LONG(step); if (!EXCL(range)) end += 1; i = FIX2LONG(b); while (i < end) { rb_yield(LONG2NUM(i)); if (i + unit < i) break; i += unit; } } else if (SYMBOL_P(b) && SYMBOL_P(e)) { /* symbols are special */ VALUE args[2], iter[2]; args[0] = rb_sym_to_s(e); args[1] = EXCL(range) ? Qtrue : Qfalse; iter[0] = INT2FIX(1); iter[1] = step; rb_block_call(rb_sym_to_s(b), rb_intern("upto"), 2, args, sym_step_i, (VALUE)iter); } else if (ruby_float_step(b, e, step, EXCL(range))) { /* done */ } else if (rb_obj_is_kind_of(b, rb_cNumeric) || !NIL_P(rb_check_to_integer(b, "to_int")) || !NIL_P(rb_check_to_integer(e, "to_int"))) { ID op = EXCL(range) ? '<' : idLE; VALUE v = b; int i = 0; while (RTEST(rb_funcall(v, op, 1, e))) { rb_yield(v); i++; v = rb_funcall(b, '+', 1, rb_funcall(INT2NUM(i), '*', 1, step)); } } else { tmp = rb_check_string_type(b); if (!NIL_P(tmp)) { VALUE args[2], iter[2]; b = tmp; args[0] = e; args[1] = EXCL(range) ? Qtrue : Qfalse; iter[0] = INT2FIX(1); iter[1] = step; rb_block_call(b, rb_intern("upto"), 2, args, step_i, (VALUE)iter); } else { VALUE args[2]; if (!discrete_object_p(b)) { rb_raise(rb_eTypeError, "can't iterate from %s", rb_obj_classname(b)); } args[0] = INT2FIX(1); args[1] = step; range_each_func(range, step_i, (VALUE)args); } } return range; }
static VALUE range_step(int argc, VALUE *argv, VALUE range) { VALUE b, e, step; long unit; RETURN_ENUMERATOR(range, argc, argv); b = RANGE_BEG(range); e = RANGE_END(range); if (rb_scan_args(argc, argv, "01", &step) == 0) { step = INT2FIX(1); unit = 1; } else if (FIXNUM_P(step)) { unit = NUM2LONG(step); } else { VALUE tmp = rb_to_int(step); unit = rb_cmpint(tmp, step, INT2FIX(0)); step = tmp; } if (unit < 0) { rb_raise(rb_eArgError, "step can't be negative"); } if (unit == 0) rb_raise(rb_eArgError, "step can't be 0"); if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */ long end = FIX2LONG(e); long i; if (!EXCL(range)) end += 1; i = FIX2LONG(b); while (i < end) { rb_yield(LONG2NUM(i)); if (i + unit < i) break; i += unit; } } else { VALUE tmp = rb_check_string_type(b); if (!NIL_P(tmp)) { VALUE args[2], iter[2]; b = tmp; args[0] = e; args[1] = EXCL(range) ? Qtrue : Qfalse; iter[0] = INT2FIX(1); iter[1] = step; rb_block_call(b, rb_intern("upto"), 2, args, step_i, (VALUE)iter); } else if (rb_obj_is_kind_of(b, rb_cNumeric)) { ID c = rb_intern(EXCL(range) ? "<" : "<="); if (rb_equal(step, INT2FIX(0))) rb_raise(rb_eArgError, "step can't be 0"); while (RTEST(rb_funcall(b, c, 1, e))) { rb_yield(b); b = rb_funcall(b, '+', 1, step); } } else { VALUE args[2]; if (!rb_respond_to(b, id_succ)) { rb_raise(rb_eTypeError, "can't iterate from %s", rb_obj_classname(b)); } args[0] = INT2FIX(1); args[1] = step; range_each_func(range, step_i, b, e, args); } } return range; }
static VALUE range_begin(VALUE range, SEL sel) { return RANGE_BEG(range); }
static VALUE range_step(VALUE range, SEL sel, int argc, VALUE *argv) { VALUE b, e, step, tmp; RETURN_ENUMERATOR(range, argc, argv); b = RANGE_BEG(range); e = RANGE_END(range); if (argc == 0) { step = INT2FIX(1); } else { rb_scan_args(argc, argv, "01", &step); if (!rb_obj_is_kind_of(step, rb_cNumeric)) { step = rb_to_int(step); } VALUE zero = INT2FIX(0); if (rb_vm_call(step, selLT, 1, &zero)) { rb_raise(rb_eArgError, "step can't be negative"); } else if (!rb_vm_call(step, selGT, 1, &zero)) { rb_raise(rb_eArgError, "step can't be 0"); } } if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */ long end = FIX2LONG(e); long i, unit = FIX2LONG(step); if (!EXCL(range)) end += 1; i = FIX2LONG(b); while (i < end) { rb_yield(LONG2NUM(i)); RETURN_IF_BROKEN(); if (i + unit < i) break; i += unit; } } else if (SYMBOL_P(b) && SYMBOL_P(e)) { /* symbols are special */ VALUE args[2]; VALUE iter[2]; args[0] = rb_sym_to_s(e); args[1] = EXCL(range) ? Qtrue : Qfalse; iter[0] = INT2FIX(1); iter[1] = step; rb_objc_block_call(rb_sym_to_s(b), selUpto, 2, args, sym_step_i, (VALUE)iter); } else if (ruby_float_step(b, e, step, EXCL(range))) { /* done */ } else if (rb_obj_is_kind_of(b, rb_cNumeric) || !NIL_P(rb_check_to_integer(b, "to_int")) || !NIL_P(rb_check_to_integer(e, "to_int"))) { SEL op = EXCL(range) ? selLT : selLE; VALUE v = b; int i = 0; while (RTEST(rb_vm_call(v, op, 1, &e))) { rb_yield(v); RETURN_IF_BROKEN(); i++; VALUE tmp = rb_vm_call(INT2NUM(i), selMULT, 1, &step); v = rb_vm_call(b, selPLUS, 1, &tmp); } } else { tmp = rb_check_string_type(b); if (!NIL_P(tmp)) { VALUE args[2], iter[2]; b = tmp; args[0] = e; args[1] = EXCL(range) ? Qtrue : Qfalse; iter[0] = INT2FIX(1); iter[1] = step; rb_objc_block_call(b, selUpto, 2, args, step_i, (VALUE)iter); } else { VALUE args[2]; if (!discrete_object_p(b)) { rb_raise(rb_eTypeError, "can't iterate from %s", rb_obj_classname(b)); } args[0] = INT2FIX(1); args[1] = step; return range_each_func(range, step_i, args); } } return range; }
static VALUE range_bsearch(VALUE range) { VALUE beg, end; int smaller, satisfied = 0; /* Implementation notes: * Floats are handled by mapping them to 64 bits integers. * Apart from sign issues, floats and their 64 bits integer have the * same order, assuming they are represented as exponent followed * by the mantissa. This is true with or without implicit bit. * * Finding the average of two ints needs to be careful about * potential overflow (since float to long can use 64 bits) * as well as the fact that -1/2 can be 0 or -1 in C89. * * Note that -0.0 is mapped to the same int as 0.0 as we don't want * (-1...0.0).bsearch to yield -0.0. */ #define BSEARCH_CHECK(val) \ do { \ VALUE v = rb_yield(val); \ if (FIXNUM_P(v)) { \ if (FIX2INT(v) == 0) return val; \ smaller = FIX2INT(v) < 0; \ } \ else if (v == Qtrue) { \ satisfied = 1; \ smaller = 1; \ } \ else if (v == Qfalse || v == Qnil) { \ smaller = 0; \ } \ else if (rb_obj_is_kind_of(v, rb_cNumeric)) { \ int cmp = rb_cmpint(rb_funcall(v, id_cmp, 1, INT2FIX(0)), v, INT2FIX(0)); \ if (!cmp) return val; \ smaller = cmp < 0; \ } \ else { \ rb_raise(rb_eTypeError, "wrong argument type %s" \ " (must be numeric, true, false or nil)", \ rb_obj_classname(v)); \ } \ } while (0) #define BSEARCH(conv) \ do { \ RETURN_ENUMERATOR(range, 0, 0); \ if (EXCL(range)) high--; \ org_high = high; \ while (low < high) { \ mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \ : (low < -high) ? -((-1 - low - high)/2 + 1) : (low + high) / 2; \ BSEARCH_CHECK(conv(mid)); \ if (smaller) { \ high = mid; \ } \ else { \ low = mid + 1; \ } \ } \ if (low == org_high) { \ BSEARCH_CHECK(conv(low)); \ if (!smaller) return Qnil; \ } \ if (!satisfied) return Qnil; \ return conv(low); \ } while (0) beg = RANGE_BEG(range); end = RANGE_END(range); if (FIXNUM_P(beg) && FIXNUM_P(end)) { long low = FIX2LONG(beg); long high = FIX2LONG(end); long mid, org_high; BSEARCH(INT2FIX); } #if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T) else if (RB_TYPE_P(beg, T_FLOAT) || RB_TYPE_P(end, T_FLOAT)) { int64_t low = double_as_int64(RFLOAT_VALUE(rb_Float(beg))); int64_t high = double_as_int64(RFLOAT_VALUE(rb_Float(end))); int64_t mid, org_high; BSEARCH(int64_as_double_to_num); } #endif else if (is_integer_p(beg) && is_integer_p(end)) { VALUE low = rb_to_int(beg); VALUE high = rb_to_int(end); VALUE mid, org_high; RETURN_ENUMERATOR(range, 0, 0); if (EXCL(range)) high = rb_funcall(high, '-', 1, INT2FIX(1)); org_high = high; while (rb_cmpint(rb_funcall(low, id_cmp, 1, high), low, high) < 0) { mid = rb_funcall(rb_funcall(high, '+', 1, low), id_div, 1, INT2FIX(2)); BSEARCH_CHECK(mid); if (smaller) { high = mid; } else { low = rb_funcall(mid, '+', 1, INT2FIX(1)); } } if (rb_equal(low, org_high)) { BSEARCH_CHECK(low); if (!smaller) return Qnil; } if (!satisfied) return Qnil; return low; } else { rb_raise(rb_eTypeError, "can't do binary search for %s", rb_obj_classname(beg)); } return range; }