00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "ruby/ruby.h"
00013 #include "ruby/encoding.h"
00014 #include "internal.h"
00015 #include "id.h"
00016
00017 #ifdef HAVE_FLOAT_H
00018 #include <float.h>
00019 #endif
00020 #include <math.h>
00021
00022 VALUE rb_cRange;
00023 static ID id_cmp, id_succ, id_beg, id_end, id_excl, id_integer_p, id_div;
00024
00025 #define RANGE_BEG(r) (RSTRUCT(r)->as.ary[0])
00026 #define RANGE_END(r) (RSTRUCT(r)->as.ary[1])
00027 #define RANGE_EXCL(r) (RSTRUCT(r)->as.ary[2])
00028 #define RANGE_SET_BEG(r, v) (RSTRUCT_SET(r, 0, v))
00029 #define RANGE_SET_END(r, v) (RSTRUCT_SET(r, 1, v))
00030 #define RANGE_SET_EXCL(r, v) (RSTRUCT_SET(r, 2, v))
00031 #define RBOOL(v) ((v) ? Qtrue : Qfalse)
00032
00033 #define EXCL(r) RTEST(RANGE_EXCL(r))
00034
00035 static VALUE
00036 range_failed(void)
00037 {
00038 rb_raise(rb_eArgError, "bad value for range");
00039 return Qnil;
00040 }
00041
00042 static VALUE
00043 range_check(VALUE *args)
00044 {
00045 return rb_funcall(args[0], id_cmp, 1, args[1]);
00046 }
00047
00048 static void
00049 range_init(VALUE range, VALUE beg, VALUE end, VALUE exclude_end)
00050 {
00051 VALUE args[2];
00052
00053 args[0] = beg;
00054 args[1] = end;
00055
00056 if (!FIXNUM_P(beg) || !FIXNUM_P(end)) {
00057 VALUE v;
00058
00059 v = rb_rescue(range_check, (VALUE)args, range_failed, 0);
00060 if (NIL_P(v))
00061 range_failed();
00062 }
00063
00064 RANGE_SET_EXCL(range, exclude_end);
00065 RANGE_SET_BEG(range, beg);
00066 RANGE_SET_END(range, end);
00067 }
00068
00069 VALUE
00070 rb_range_new(VALUE beg, VALUE end, int exclude_end)
00071 {
00072 VALUE range = rb_obj_alloc(rb_cRange);
00073
00074 range_init(range, beg, end, RBOOL(exclude_end));
00075 return range;
00076 }
00077
00078 static void
00079 range_modify(VALUE range)
00080 {
00081
00082 if (RANGE_EXCL(range) != Qnil) {
00083 rb_name_error(idInitialize, "`initialize' called twice");
00084 }
00085 }
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 static VALUE
00097 range_initialize(int argc, VALUE *argv, VALUE range)
00098 {
00099 VALUE beg, end, flags;
00100
00101 rb_scan_args(argc, argv, "21", &beg, &end, &flags);
00102 range_modify(range);
00103 range_init(range, beg, end, RBOOL(RTEST(flags)));
00104 return Qnil;
00105 }
00106
00107
00108 static VALUE
00109 range_initialize_copy(VALUE range, VALUE orig)
00110 {
00111 range_modify(range);
00112 rb_struct_init_copy(range, orig);
00113 return range;
00114 }
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126 static VALUE
00127 range_exclude_end_p(VALUE range)
00128 {
00129 return EXCL(range) ? Qtrue : Qfalse;
00130 }
00131
00132 static VALUE
00133 recursive_equal(VALUE range, VALUE obj, int recur)
00134 {
00135 if (recur) return Qtrue;
00136 if (!rb_equal(RANGE_BEG(range), RANGE_BEG(obj)))
00137 return Qfalse;
00138 if (!rb_equal(RANGE_END(range), RANGE_END(obj)))
00139 return Qfalse;
00140
00141 if (EXCL(range) != EXCL(obj))
00142 return Qfalse;
00143 return Qtrue;
00144 }
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161 static VALUE
00162 range_eq(VALUE range, VALUE obj)
00163 {
00164 if (range == obj)
00165 return Qtrue;
00166 if (!rb_obj_is_kind_of(obj, rb_cRange))
00167 return Qfalse;
00168
00169 return rb_exec_recursive_paired(recursive_equal, range, obj, obj);
00170 }
00171
00172 static int
00173 r_lt(VALUE a, VALUE b)
00174 {
00175 VALUE r = rb_funcall(a, id_cmp, 1, b);
00176
00177 if (NIL_P(r))
00178 return (int)Qfalse;
00179 if (rb_cmpint(r, a, b) < 0)
00180 return (int)Qtrue;
00181 return (int)Qfalse;
00182 }
00183
00184 static int
00185 r_le(VALUE a, VALUE b)
00186 {
00187 int c;
00188 VALUE r = rb_funcall(a, id_cmp, 1, b);
00189
00190 if (NIL_P(r))
00191 return (int)Qfalse;
00192 c = rb_cmpint(r, a, b);
00193 if (c == 0)
00194 return (int)INT2FIX(0);
00195 if (c < 0)
00196 return (int)Qtrue;
00197 return (int)Qfalse;
00198 }
00199
00200
00201 static VALUE
00202 recursive_eql(VALUE range, VALUE obj, int recur)
00203 {
00204 if (recur) return Qtrue;
00205 if (!rb_eql(RANGE_BEG(range), RANGE_BEG(obj)))
00206 return Qfalse;
00207 if (!rb_eql(RANGE_END(range), RANGE_END(obj)))
00208 return Qfalse;
00209
00210 if (EXCL(range) != EXCL(obj))
00211 return Qfalse;
00212 return Qtrue;
00213 }
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229 static VALUE
00230 range_eql(VALUE range, VALUE obj)
00231 {
00232 if (range == obj)
00233 return Qtrue;
00234 if (!rb_obj_is_kind_of(obj, rb_cRange))
00235 return Qfalse;
00236 return rb_exec_recursive_paired(recursive_eql, range, obj, obj);
00237 }
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 static VALUE
00249 range_hash(VALUE range)
00250 {
00251 st_index_t hash = EXCL(range);
00252 VALUE v;
00253
00254 hash = rb_hash_start(hash);
00255 v = rb_hash(RANGE_BEG(range));
00256 hash = rb_hash_uint(hash, NUM2LONG(v));
00257 v = rb_hash(RANGE_END(range));
00258 hash = rb_hash_uint(hash, NUM2LONG(v));
00259 hash = rb_hash_uint(hash, EXCL(range) << 24);
00260 hash = rb_hash_end(hash);
00261
00262 return LONG2FIX(hash);
00263 }
00264
00265 static void
00266 range_each_func(VALUE range, rb_block_call_func *func, VALUE arg)
00267 {
00268 int c;
00269 VALUE b = RANGE_BEG(range);
00270 VALUE e = RANGE_END(range);
00271 VALUE v = b;
00272
00273 if (EXCL(range)) {
00274 while (r_lt(v, e)) {
00275 (*func) (v, arg, 0, 0, 0);
00276 v = rb_funcall(v, id_succ, 0, 0);
00277 }
00278 }
00279 else {
00280 while ((c = r_le(v, e)) != Qfalse) {
00281 (*func) (v, arg, 0, 0, 0);
00282 if (c == (int)INT2FIX(0))
00283 break;
00284 v = rb_funcall(v, id_succ, 0, 0);
00285 }
00286 }
00287 }
00288
00289 static VALUE
00290 sym_step_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg))
00291 {
00292 VALUE *iter = (VALUE *)arg;
00293
00294 if (FIXNUM_P(iter[0])) {
00295 iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG;
00296 }
00297 else {
00298 iter[0] = rb_funcall(iter[0], '-', 1, INT2FIX(1));
00299 }
00300 if (iter[0] == INT2FIX(0)) {
00301 rb_yield(rb_str_intern(i));
00302 iter[0] = iter[1];
00303 }
00304 return Qnil;
00305 }
00306
00307 static VALUE
00308 step_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg))
00309 {
00310 VALUE *iter = (VALUE *)arg;
00311
00312 if (FIXNUM_P(iter[0])) {
00313 iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG;
00314 }
00315 else {
00316 iter[0] = rb_funcall(iter[0], '-', 1, INT2FIX(1));
00317 }
00318 if (iter[0] == INT2FIX(0)) {
00319 rb_yield(i);
00320 iter[0] = iter[1];
00321 }
00322 return Qnil;
00323 }
00324
00325 static int
00326 discrete_object_p(VALUE obj)
00327 {
00328 if (rb_obj_is_kind_of(obj, rb_cTime)) return FALSE;
00329 return rb_respond_to(obj, id_succ);
00330 }
00331
00332 static int
00333 linear_object_p(VALUE obj)
00334 {
00335 if (FIXNUM_P(obj) || FLONUM_P(obj)) return TRUE;
00336 if (SPECIAL_CONST_P(obj)) return FALSE;
00337 switch (BUILTIN_TYPE(obj)) {
00338 case T_FLOAT:
00339 case T_BIGNUM:
00340 return TRUE;
00341 }
00342 if (rb_obj_is_kind_of(obj, rb_cNumeric)) return TRUE;
00343 if (rb_obj_is_kind_of(obj, rb_cTime)) return TRUE;
00344 return FALSE;
00345 }
00346
00347 static VALUE
00348 range_step_size(VALUE range, VALUE args, VALUE eobj)
00349 {
00350 VALUE b = RANGE_BEG(range), e = RANGE_END(range);
00351 VALUE step = INT2FIX(1);
00352 if (args) {
00353 step = RARRAY_AREF(args, 0);
00354 if (!rb_obj_is_kind_of(step, rb_cNumeric)) {
00355 step = rb_to_int(step);
00356 }
00357 }
00358 if (rb_funcall(step, '<', 1, INT2FIX(0))) {
00359 rb_raise(rb_eArgError, "step can't be negative");
00360 }
00361 else if (!rb_funcall(step, '>', 1, INT2FIX(0))) {
00362 rb_raise(rb_eArgError, "step can't be 0");
00363 }
00364
00365 if (rb_obj_is_kind_of(b, rb_cNumeric) && rb_obj_is_kind_of(e, rb_cNumeric)) {
00366 return ruby_num_interval_step_size(b, e, step, EXCL(range));
00367 }
00368 return Qnil;
00369 }
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 static VALUE
00406 range_step(int argc, VALUE *argv, VALUE range)
00407 {
00408 VALUE b, e, step, tmp;
00409
00410 RETURN_SIZED_ENUMERATOR(range, argc, argv, range_step_size);
00411
00412 b = RANGE_BEG(range);
00413 e = RANGE_END(range);
00414 if (argc == 0) {
00415 step = INT2FIX(1);
00416 }
00417 else {
00418 rb_scan_args(argc, argv, "01", &step);
00419 if (!rb_obj_is_kind_of(step, rb_cNumeric)) {
00420 step = rb_to_int(step);
00421 }
00422 if (rb_funcall(step, '<', 1, INT2FIX(0))) {
00423 rb_raise(rb_eArgError, "step can't be negative");
00424 }
00425 else if (!rb_funcall(step, '>', 1, INT2FIX(0))) {
00426 rb_raise(rb_eArgError, "step can't be 0");
00427 }
00428 }
00429
00430 if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) {
00431 long end = FIX2LONG(e);
00432 long i, unit = FIX2LONG(step);
00433
00434 if (!EXCL(range))
00435 end += 1;
00436 i = FIX2LONG(b);
00437 while (i < end) {
00438 rb_yield(LONG2NUM(i));
00439 if (i + unit < i) break;
00440 i += unit;
00441 }
00442
00443 }
00444 else if (SYMBOL_P(b) && SYMBOL_P(e)) {
00445 VALUE args[2], iter[2];
00446
00447 args[0] = rb_sym_to_s(e);
00448 args[1] = EXCL(range) ? Qtrue : Qfalse;
00449 iter[0] = INT2FIX(1);
00450 iter[1] = step;
00451 rb_block_call(rb_sym_to_s(b), rb_intern("upto"), 2, args, sym_step_i, (VALUE)iter);
00452 }
00453 else if (ruby_float_step(b, e, step, EXCL(range))) {
00454
00455 }
00456 else if (rb_obj_is_kind_of(b, rb_cNumeric) ||
00457 !NIL_P(rb_check_to_integer(b, "to_int")) ||
00458 !NIL_P(rb_check_to_integer(e, "to_int"))) {
00459 ID op = EXCL(range) ? '<' : idLE;
00460 VALUE v = b;
00461 int i = 0;
00462
00463 while (RTEST(rb_funcall(v, op, 1, e))) {
00464 rb_yield(v);
00465 i++;
00466 v = rb_funcall(b, '+', 1, rb_funcall(INT2NUM(i), '*', 1, step));
00467 }
00468 }
00469 else {
00470 tmp = rb_check_string_type(b);
00471
00472 if (!NIL_P(tmp)) {
00473 VALUE args[2], iter[2];
00474
00475 b = tmp;
00476 args[0] = e;
00477 args[1] = EXCL(range) ? Qtrue : Qfalse;
00478 iter[0] = INT2FIX(1);
00479 iter[1] = step;
00480 rb_block_call(b, rb_intern("upto"), 2, args, step_i, (VALUE)iter);
00481 }
00482 else {
00483 VALUE args[2];
00484
00485 if (!discrete_object_p(b)) {
00486 rb_raise(rb_eTypeError, "can't iterate from %s",
00487 rb_obj_classname(b));
00488 }
00489 args[0] = INT2FIX(1);
00490 args[1] = step;
00491 range_each_func(range, step_i, (VALUE)args);
00492 }
00493 }
00494 return range;
00495 }
00496
00497 #if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
00498 union int64_double {
00499 int64_t i;
00500 double d;
00501 };
00502
00503 static VALUE
00504 int64_as_double_to_num(int64_t i)
00505 {
00506 union int64_double convert;
00507 if (i < 0) {
00508 convert.i = -i;
00509 return DBL2NUM(-convert.d);
00510 }
00511 else {
00512 convert.i = i;
00513 return DBL2NUM(convert.d);
00514 }
00515 }
00516
00517 static int64_t
00518 double_as_int64(double d)
00519 {
00520 union int64_double convert;
00521 convert.d = fabs(d);
00522 return d < 0 ? -convert.i : convert.i;
00523 }
00524 #endif
00525
00526 static int
00527 is_integer_p(VALUE v)
00528 {
00529 VALUE is_int = rb_check_funcall(v, id_integer_p, 0, 0);
00530 return RTEST(is_int) && is_int != Qundef;
00531 }
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585 static VALUE
00586 range_bsearch(VALUE range)
00587 {
00588 VALUE beg, end;
00589 int smaller, satisfied = 0;
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605 #define BSEARCH_CHECK(val) \
00606 do { \
00607 VALUE v = rb_yield(val); \
00608 if (FIXNUM_P(v)) { \
00609 if (FIX2INT(v) == 0) return val; \
00610 smaller = FIX2INT(v) < 0; \
00611 } \
00612 else if (v == Qtrue) { \
00613 satisfied = 1; \
00614 smaller = 1; \
00615 } \
00616 else if (v == Qfalse || v == Qnil) { \
00617 smaller = 0; \
00618 } \
00619 else if (rb_obj_is_kind_of(v, rb_cNumeric)) { \
00620 int cmp = rb_cmpint(rb_funcall(v, id_cmp, 1, INT2FIX(0)), v, INT2FIX(0)); \
00621 if (!cmp) return val; \
00622 smaller = cmp < 0; \
00623 } \
00624 else { \
00625 rb_raise(rb_eTypeError, "wrong argument type %s" \
00626 " (must be numeric, true, false or nil)", \
00627 rb_obj_classname(v)); \
00628 } \
00629 } while (0)
00630
00631 #define BSEARCH(conv) \
00632 do { \
00633 RETURN_ENUMERATOR(range, 0, 0); \
00634 if (EXCL(range)) high--; \
00635 org_high = high; \
00636 while (low < high) { \
00637 mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \
00638 : (low < -high) ? -((-1 - low - high)/2 + 1) : (low + high) / 2; \
00639 BSEARCH_CHECK(conv(mid)); \
00640 if (smaller) { \
00641 high = mid; \
00642 } \
00643 else { \
00644 low = mid + 1; \
00645 } \
00646 } \
00647 if (low == org_high) { \
00648 BSEARCH_CHECK(conv(low)); \
00649 if (!smaller) return Qnil; \
00650 } \
00651 if (!satisfied) return Qnil; \
00652 return conv(low); \
00653 } while (0)
00654
00655
00656 beg = RANGE_BEG(range);
00657 end = RANGE_END(range);
00658
00659 if (FIXNUM_P(beg) && FIXNUM_P(end)) {
00660 long low = FIX2LONG(beg);
00661 long high = FIX2LONG(end);
00662 long mid, org_high;
00663 BSEARCH(INT2FIX);
00664 }
00665 #if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
00666 else if (RB_TYPE_P(beg, T_FLOAT) || RB_TYPE_P(end, T_FLOAT)) {
00667 int64_t low = double_as_int64(RFLOAT_VALUE(rb_Float(beg)));
00668 int64_t high = double_as_int64(RFLOAT_VALUE(rb_Float(end)));
00669 int64_t mid, org_high;
00670 BSEARCH(int64_as_double_to_num);
00671 }
00672 #endif
00673 else if (is_integer_p(beg) && is_integer_p(end)) {
00674 VALUE low = rb_to_int(beg);
00675 VALUE high = rb_to_int(end);
00676 VALUE mid, org_high;
00677 RETURN_ENUMERATOR(range, 0, 0);
00678 if (EXCL(range)) high = rb_funcall(high, '-', 1, INT2FIX(1));
00679 org_high = high;
00680
00681 while (rb_cmpint(rb_funcall(low, id_cmp, 1, high), low, high) < 0) {
00682 mid = rb_funcall(rb_funcall(high, '+', 1, low), id_div, 1, INT2FIX(2));
00683 BSEARCH_CHECK(mid);
00684 if (smaller) {
00685 high = mid;
00686 }
00687 else {
00688 low = rb_funcall(mid, '+', 1, INT2FIX(1));
00689 }
00690 }
00691 if (rb_equal(low, org_high)) {
00692 BSEARCH_CHECK(low);
00693 if (!smaller) return Qnil;
00694 }
00695 if (!satisfied) return Qnil;
00696 return low;
00697 }
00698 else {
00699 rb_raise(rb_eTypeError, "can't do binary search for %s", rb_obj_classname(beg));
00700 }
00701 return range;
00702 }
00703
00704 static VALUE
00705 each_i(RB_BLOCK_CALL_FUNC_ARGLIST(v, arg))
00706 {
00707 rb_yield(v);
00708 return Qnil;
00709 }
00710
00711 static VALUE
00712 sym_each_i(RB_BLOCK_CALL_FUNC_ARGLIST(v, arg))
00713 {
00714 rb_yield(rb_str_intern(v));
00715 return Qnil;
00716 }
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730 static VALUE
00731 range_size(VALUE range)
00732 {
00733 VALUE b = RANGE_BEG(range), e = RANGE_END(range);
00734 if (rb_obj_is_kind_of(b, rb_cNumeric) && rb_obj_is_kind_of(e, rb_cNumeric)) {
00735 return ruby_num_interval_step_size(b, e, INT2FIX(1), EXCL(range));
00736 }
00737 return Qnil;
00738 }
00739
00740 static VALUE
00741 range_enum_size(VALUE range, VALUE args, VALUE eobj)
00742 {
00743 return range_size(range);
00744 }
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767 static VALUE
00768 range_each(VALUE range)
00769 {
00770 VALUE beg, end;
00771
00772 RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_size);
00773
00774 beg = RANGE_BEG(range);
00775 end = RANGE_END(range);
00776
00777 if (FIXNUM_P(beg) && FIXNUM_P(end)) {
00778 long lim = FIX2LONG(end);
00779 long i;
00780
00781 if (!EXCL(range))
00782 lim += 1;
00783 for (i = FIX2LONG(beg); i < lim; i++) {
00784 rb_yield(LONG2FIX(i));
00785 }
00786 }
00787 else if (SYMBOL_P(beg) && SYMBOL_P(end)) {
00788 VALUE args[2];
00789
00790 args[0] = rb_sym_to_s(end);
00791 args[1] = EXCL(range) ? Qtrue : Qfalse;
00792 rb_block_call(rb_sym_to_s(beg), rb_intern("upto"), 2, args, sym_each_i, 0);
00793 }
00794 else {
00795 VALUE tmp = rb_check_string_type(beg);
00796
00797 if (!NIL_P(tmp)) {
00798 VALUE args[2];
00799
00800 args[0] = end;
00801 args[1] = EXCL(range) ? Qtrue : Qfalse;
00802 rb_block_call(tmp, rb_intern("upto"), 2, args, each_i, 0);
00803 }
00804 else {
00805 if (!discrete_object_p(beg)) {
00806 rb_raise(rb_eTypeError, "can't iterate from %s",
00807 rb_obj_classname(beg));
00808 }
00809 range_each_func(range, each_i, 0);
00810 }
00811 }
00812 return range;
00813 }
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824 static VALUE
00825 range_begin(VALUE range)
00826 {
00827 return RANGE_BEG(range);
00828 }
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842 static VALUE
00843 range_end(VALUE range)
00844 {
00845 return RANGE_END(range);
00846 }
00847
00848
00849 static VALUE
00850 first_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, cbarg))
00851 {
00852 VALUE *ary = (VALUE *)cbarg;
00853 long n = NUM2LONG(ary[0]);
00854
00855 if (n <= 0) {
00856 rb_iter_break();
00857 }
00858 rb_ary_push(ary[1], i);
00859 n--;
00860 ary[0] = INT2NUM(n);
00861 return Qnil;
00862 }
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876 static VALUE
00877 range_first(int argc, VALUE *argv, VALUE range)
00878 {
00879 VALUE n, ary[2];
00880
00881 if (argc == 0) return RANGE_BEG(range);
00882
00883 rb_scan_args(argc, argv, "1", &n);
00884 ary[0] = n;
00885 ary[1] = rb_ary_new2(NUM2LONG(n));
00886 rb_block_call(range, idEach, 0, 0, first_i, (VALUE)ary);
00887
00888 return ary[1];
00889 }
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909 static VALUE
00910 range_last(int argc, VALUE *argv, VALUE range)
00911 {
00912 if (argc == 0) return RANGE_END(range);
00913 return rb_ary_last(argc, argv, rb_Array(range));
00914 }
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932 static VALUE
00933 range_min(VALUE range)
00934 {
00935 if (rb_block_given_p()) {
00936 return rb_call_super(0, 0);
00937 }
00938 else {
00939 VALUE b = RANGE_BEG(range);
00940 VALUE e = RANGE_END(range);
00941 int c = rb_cmpint(rb_funcall(b, id_cmp, 1, e), b, e);
00942
00943 if (c > 0 || (c == 0 && EXCL(range)))
00944 return Qnil;
00945 return b;
00946 }
00947 }
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963 static VALUE
00964 range_max(VALUE range)
00965 {
00966 VALUE e = RANGE_END(range);
00967 int nm = FIXNUM_P(e) || rb_obj_is_kind_of(e, rb_cNumeric);
00968
00969 if (rb_block_given_p() || (EXCL(range) && !nm)) {
00970 return rb_call_super(0, 0);
00971 }
00972 else {
00973 VALUE b = RANGE_BEG(range);
00974 int c = rb_cmpint(rb_funcall(b, id_cmp, 1, e), b, e);
00975
00976 if (c > 0)
00977 return Qnil;
00978 if (EXCL(range)) {
00979 if (!FIXNUM_P(e) && !rb_obj_is_kind_of(e, rb_cInteger)) {
00980 rb_raise(rb_eTypeError, "cannot exclude non Integer end value");
00981 }
00982 if (c == 0) return Qnil;
00983 if (!FIXNUM_P(b) && !rb_obj_is_kind_of(b,rb_cInteger)) {
00984 rb_raise(rb_eTypeError, "cannot exclude end value with non Integer begin value");
00985 }
00986 if (FIXNUM_P(e)) {
00987 return LONG2NUM(FIX2LONG(e) - 1);
00988 }
00989 return rb_funcall(e, '-', 1, INT2FIX(1));
00990 }
00991 return e;
00992 }
00993 }
00994
00995 int
00996 rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
00997 {
00998 VALUE b, e;
00999 int excl;
01000
01001 if (rb_obj_is_kind_of(range, rb_cRange)) {
01002 b = RANGE_BEG(range);
01003 e = RANGE_END(range);
01004 excl = EXCL(range);
01005 }
01006 else {
01007 if (!rb_respond_to(range, id_beg)) return (int)Qfalse;
01008 if (!rb_respond_to(range, id_end)) return (int)Qfalse;
01009 b = rb_funcall(range, id_beg, 0);
01010 e = rb_funcall(range, id_end, 0);
01011 excl = RTEST(rb_funcall(range, rb_intern("exclude_end?"), 0));
01012 }
01013 *begp = b;
01014 *endp = e;
01015 *exclp = excl;
01016 return (int)Qtrue;
01017 }
01018
01019 VALUE
01020 rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
01021 {
01022 long beg, end, origbeg, origend;
01023 VALUE b, e;
01024 int excl;
01025
01026 if (!rb_range_values(range, &b, &e, &excl))
01027 return Qfalse;
01028 beg = NUM2LONG(b);
01029 end = NUM2LONG(e);
01030 origbeg = beg;
01031 origend = end;
01032 if (beg < 0) {
01033 beg += len;
01034 if (beg < 0)
01035 goto out_of_range;
01036 }
01037 if (end < 0)
01038 end += len;
01039 if (!excl)
01040 end++;
01041 if (err == 0 || err == 2) {
01042 if (beg > len)
01043 goto out_of_range;
01044 if (end > len)
01045 end = len;
01046 }
01047 len = end - beg;
01048 if (len < 0)
01049 len = 0;
01050
01051 *begp = beg;
01052 *lenp = len;
01053 return Qtrue;
01054
01055 out_of_range:
01056 if (err) {
01057 rb_raise(rb_eRangeError, "%ld..%s%ld out of range",
01058 origbeg, excl ? "." : "", origend);
01059 }
01060 return Qnil;
01061 }
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071 static VALUE
01072 range_to_s(VALUE range)
01073 {
01074 VALUE str, str2;
01075
01076 str = rb_obj_as_string(RANGE_BEG(range));
01077 str2 = rb_obj_as_string(RANGE_END(range));
01078 str = rb_str_dup(str);
01079 rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
01080 rb_str_append(str, str2);
01081 OBJ_INFECT(str, range);
01082
01083 return str;
01084 }
01085
01086 static VALUE
01087 inspect_range(VALUE range, VALUE dummy, int recur)
01088 {
01089 VALUE str, str2;
01090
01091 if (recur) {
01092 return rb_str_new2(EXCL(range) ? "(... ... ...)" : "(... .. ...)");
01093 }
01094 str = rb_inspect(RANGE_BEG(range));
01095 str2 = rb_inspect(RANGE_END(range));
01096 str = rb_str_dup(str);
01097 rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
01098 rb_str_append(str, str2);
01099 OBJ_INFECT(str, range);
01100
01101 return str;
01102 }
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114 static VALUE
01115 range_inspect(VALUE range)
01116 {
01117 return rb_exec_recursive(inspect_range, range, 0);
01118 }
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139 static VALUE
01140 range_eqq(VALUE range, VALUE val)
01141 {
01142 return rb_funcall(range, rb_intern("include?"), 1, val);
01143 }
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160 static VALUE
01161 range_include(VALUE range, VALUE val)
01162 {
01163 VALUE beg = RANGE_BEG(range);
01164 VALUE end = RANGE_END(range);
01165 int nv = FIXNUM_P(beg) || FIXNUM_P(end) ||
01166 linear_object_p(beg) || linear_object_p(end);
01167
01168 if (nv ||
01169 !NIL_P(rb_check_to_integer(beg, "to_int")) ||
01170 !NIL_P(rb_check_to_integer(end, "to_int"))) {
01171 if (r_le(beg, val)) {
01172 if (EXCL(range)) {
01173 if (r_lt(val, end))
01174 return Qtrue;
01175 }
01176 else {
01177 if (r_le(val, end))
01178 return Qtrue;
01179 }
01180 }
01181 return Qfalse;
01182 }
01183 else if (RB_TYPE_P(beg, T_STRING) && RB_TYPE_P(end, T_STRING) &&
01184 RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) {
01185 if (NIL_P(val)) return Qfalse;
01186 if (RB_TYPE_P(val, T_STRING)) {
01187 if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1)
01188 return Qfalse;
01189 else {
01190 char b = RSTRING_PTR(beg)[0];
01191 char e = RSTRING_PTR(end)[0];
01192 char v = RSTRING_PTR(val)[0];
01193
01194 if (ISASCII(b) && ISASCII(e) && ISASCII(v)) {
01195 if (b <= v && v < e) return Qtrue;
01196 if (!EXCL(range) && v == e) return Qtrue;
01197 return Qfalse;
01198 }
01199 }
01200 }
01201 }
01202
01203 return rb_call_super(1, &val);
01204 }
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222 static VALUE
01223 range_cover(VALUE range, VALUE val)
01224 {
01225 VALUE beg, end;
01226
01227 beg = RANGE_BEG(range);
01228 end = RANGE_END(range);
01229 if (r_le(beg, val)) {
01230 if (EXCL(range)) {
01231 if (r_lt(val, end))
01232 return Qtrue;
01233 }
01234 else {
01235 if (r_le(val, end))
01236 return Qtrue;
01237 }
01238 }
01239 return Qfalse;
01240 }
01241
01242 static VALUE
01243 range_dumper(VALUE range)
01244 {
01245 VALUE v;
01246 NEWOBJ_OF(m, struct RObject, rb_cObject, T_OBJECT | (RGENGC_WB_PROTECTED_OBJECT ? FL_WB_PROTECTED : 1));
01247
01248 v = (VALUE)m;
01249
01250 rb_ivar_set(v, id_excl, RANGE_EXCL(range));
01251 rb_ivar_set(v, id_beg, RANGE_BEG(range));
01252 rb_ivar_set(v, id_end, RANGE_END(range));
01253 return v;
01254 }
01255
01256 static VALUE
01257 range_loader(VALUE range, VALUE obj)
01258 {
01259 if (!RB_TYPE_P(obj, T_OBJECT) || RBASIC(obj)->klass != rb_cObject) {
01260 rb_raise(rb_eTypeError, "not a dumped range object");
01261 }
01262
01263 range_modify(range);
01264 RANGE_SET_BEG(range, rb_ivar_get(obj, id_beg));
01265 RANGE_SET_END(range, rb_ivar_get(obj, id_end));
01266 RANGE_SET_EXCL(range, rb_ivar_get(obj, id_excl));
01267 return range;
01268 }
01269
01270 static VALUE
01271 range_alloc(VALUE klass)
01272 {
01273
01274
01275 return rb_struct_alloc_noinit(klass);
01276 }
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335 void
01336 Init_Range(void)
01337 {
01338 #undef rb_intern
01339 #define rb_intern(str) rb_intern_const(str)
01340
01341 id_cmp = rb_intern("<=>");
01342 id_succ = rb_intern("succ");
01343 id_beg = rb_intern("begin");
01344 id_end = rb_intern("end");
01345 id_excl = rb_intern("excl");
01346 id_integer_p = rb_intern("integer?");
01347 id_div = rb_intern("div");
01348
01349 rb_cRange = rb_struct_define_without_accessor(
01350 "Range", rb_cObject, range_alloc,
01351 "begin", "end", "excl", NULL);
01352
01353 rb_include_module(rb_cRange, rb_mEnumerable);
01354 rb_marshal_define_compat(rb_cRange, rb_cObject, range_dumper, range_loader);
01355 rb_define_method(rb_cRange, "initialize", range_initialize, -1);
01356 rb_define_method(rb_cRange, "initialize_copy", range_initialize_copy, 1);
01357 rb_define_method(rb_cRange, "==", range_eq, 1);
01358 rb_define_method(rb_cRange, "===", range_eqq, 1);
01359 rb_define_method(rb_cRange, "eql?", range_eql, 1);
01360 rb_define_method(rb_cRange, "hash", range_hash, 0);
01361 rb_define_method(rb_cRange, "each", range_each, 0);
01362 rb_define_method(rb_cRange, "step", range_step, -1);
01363 rb_define_method(rb_cRange, "bsearch", range_bsearch, 0);
01364 rb_define_method(rb_cRange, "begin", range_begin, 0);
01365 rb_define_method(rb_cRange, "end", range_end, 0);
01366 rb_define_method(rb_cRange, "first", range_first, -1);
01367 rb_define_method(rb_cRange, "last", range_last, -1);
01368 rb_define_method(rb_cRange, "min", range_min, 0);
01369 rb_define_method(rb_cRange, "max", range_max, 0);
01370 rb_define_method(rb_cRange, "size", range_size, 0);
01371 rb_define_method(rb_cRange, "to_s", range_to_s, 0);
01372 rb_define_method(rb_cRange, "inspect", range_inspect, 0);
01373
01374 rb_define_method(rb_cRange, "exclude_end?", range_exclude_end_p, 0);
01375
01376 rb_define_method(rb_cRange, "member?", range_include, 1);
01377 rb_define_method(rb_cRange, "include?", range_include, 1);
01378 rb_define_method(rb_cRange, "cover?", range_cover, 1);
01379 }
01380