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 VALUE
00333 range_step_size(VALUE range, VALUE args, VALUE eobj)
00334 {
00335 VALUE b = RANGE_BEG(range), e = RANGE_END(range);
00336 VALUE step = INT2FIX(1);
00337 if (args) {
00338 step = RARRAY_AREF(args, 0);
00339 if (!rb_obj_is_kind_of(step, rb_cNumeric)) {
00340 step = rb_to_int(step);
00341 }
00342 }
00343 if (rb_funcall(step, '<', 1, INT2FIX(0))) {
00344 rb_raise(rb_eArgError, "step can't be negative");
00345 }
00346 else if (!rb_funcall(step, '>', 1, INT2FIX(0))) {
00347 rb_raise(rb_eArgError, "step can't be 0");
00348 }
00349
00350 if (rb_obj_is_kind_of(b, rb_cNumeric) && rb_obj_is_kind_of(e, rb_cNumeric)) {
00351 return ruby_num_interval_step_size(b, e, step, EXCL(range));
00352 }
00353 return Qnil;
00354 }
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390 static VALUE
00391 range_step(int argc, VALUE *argv, VALUE range)
00392 {
00393 VALUE b, e, step, tmp;
00394
00395 RETURN_SIZED_ENUMERATOR(range, argc, argv, range_step_size);
00396
00397 b = RANGE_BEG(range);
00398 e = RANGE_END(range);
00399 if (argc == 0) {
00400 step = INT2FIX(1);
00401 }
00402 else {
00403 rb_scan_args(argc, argv, "01", &step);
00404 if (!rb_obj_is_kind_of(step, rb_cNumeric)) {
00405 step = rb_to_int(step);
00406 }
00407 if (rb_funcall(step, '<', 1, INT2FIX(0))) {
00408 rb_raise(rb_eArgError, "step can't be negative");
00409 }
00410 else if (!rb_funcall(step, '>', 1, INT2FIX(0))) {
00411 rb_raise(rb_eArgError, "step can't be 0");
00412 }
00413 }
00414
00415 if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) {
00416 long end = FIX2LONG(e);
00417 long i, unit = FIX2LONG(step);
00418
00419 if (!EXCL(range))
00420 end += 1;
00421 i = FIX2LONG(b);
00422 while (i < end) {
00423 rb_yield(LONG2NUM(i));
00424 if (i + unit < i) break;
00425 i += unit;
00426 }
00427
00428 }
00429 else if (SYMBOL_P(b) && SYMBOL_P(e)) {
00430 VALUE args[2], iter[2];
00431
00432 args[0] = rb_sym_to_s(e);
00433 args[1] = EXCL(range) ? Qtrue : Qfalse;
00434 iter[0] = INT2FIX(1);
00435 iter[1] = step;
00436 rb_block_call(rb_sym_to_s(b), rb_intern("upto"), 2, args, sym_step_i, (VALUE)iter);
00437 }
00438 else if (ruby_float_step(b, e, step, EXCL(range))) {
00439
00440 }
00441 else if (rb_obj_is_kind_of(b, rb_cNumeric) ||
00442 !NIL_P(rb_check_to_integer(b, "to_int")) ||
00443 !NIL_P(rb_check_to_integer(e, "to_int"))) {
00444 ID op = EXCL(range) ? '<' : idLE;
00445 VALUE v = b;
00446 int i = 0;
00447
00448 while (RTEST(rb_funcall(v, op, 1, e))) {
00449 rb_yield(v);
00450 i++;
00451 v = rb_funcall(b, '+', 1, rb_funcall(INT2NUM(i), '*', 1, step));
00452 }
00453 }
00454 else {
00455 tmp = rb_check_string_type(b);
00456
00457 if (!NIL_P(tmp)) {
00458 VALUE args[2], iter[2];
00459
00460 b = tmp;
00461 args[0] = e;
00462 args[1] = EXCL(range) ? Qtrue : Qfalse;
00463 iter[0] = INT2FIX(1);
00464 iter[1] = step;
00465 rb_block_call(b, rb_intern("upto"), 2, args, step_i, (VALUE)iter);
00466 }
00467 else {
00468 VALUE args[2];
00469
00470 if (!discrete_object_p(b)) {
00471 rb_raise(rb_eTypeError, "can't iterate from %s",
00472 rb_obj_classname(b));
00473 }
00474 args[0] = INT2FIX(1);
00475 args[1] = step;
00476 range_each_func(range, step_i, (VALUE)args);
00477 }
00478 }
00479 return range;
00480 }
00481
00482 #if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
00483 union int64_double {
00484 int64_t i;
00485 double d;
00486 };
00487
00488 static VALUE
00489 int64_as_double_to_num(int64_t i)
00490 {
00491 union int64_double convert;
00492 if (i < 0) {
00493 convert.i = -i;
00494 return DBL2NUM(-convert.d);
00495 }
00496 else {
00497 convert.i = i;
00498 return DBL2NUM(convert.d);
00499 }
00500 }
00501
00502 static int64_t
00503 double_as_int64(double d)
00504 {
00505 union int64_double convert;
00506 convert.d = fabs(d);
00507 return d < 0 ? -convert.i : convert.i;
00508 }
00509 #endif
00510
00511 static int
00512 is_integer_p(VALUE v)
00513 {
00514 VALUE is_int = rb_check_funcall(v, id_integer_p, 0, 0);
00515 return RTEST(is_int) && is_int != Qundef;
00516 }
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
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 static VALUE
00571 range_bsearch(VALUE range)
00572 {
00573 VALUE beg, end;
00574 int smaller, satisfied = 0;
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590 #define BSEARCH_CHECK(val) \
00591 do { \
00592 VALUE v = rb_yield(val); \
00593 if (FIXNUM_P(v)) { \
00594 if (FIX2INT(v) == 0) return val; \
00595 smaller = FIX2INT(v) < 0; \
00596 } \
00597 else if (v == Qtrue) { \
00598 satisfied = 1; \
00599 smaller = 1; \
00600 } \
00601 else if (v == Qfalse || v == Qnil) { \
00602 smaller = 0; \
00603 } \
00604 else if (rb_obj_is_kind_of(v, rb_cNumeric)) { \
00605 int cmp = rb_cmpint(rb_funcall(v, id_cmp, 1, INT2FIX(0)), v, INT2FIX(0)); \
00606 if (!cmp) return val; \
00607 smaller = cmp < 0; \
00608 } \
00609 else { \
00610 rb_raise(rb_eTypeError, "wrong argument type %s" \
00611 " (must be numeric, true, false or nil)", \
00612 rb_obj_classname(v)); \
00613 } \
00614 } while (0)
00615
00616 #define BSEARCH(conv) \
00617 do { \
00618 RETURN_ENUMERATOR(range, 0, 0); \
00619 if (EXCL(range)) high--; \
00620 org_high = high; \
00621 while (low < high) { \
00622 mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \
00623 : (low < -high) ? -((-1 - low - high)/2 + 1) : (low + high) / 2; \
00624 BSEARCH_CHECK(conv(mid)); \
00625 if (smaller) { \
00626 high = mid; \
00627 } \
00628 else { \
00629 low = mid + 1; \
00630 } \
00631 } \
00632 if (low == org_high) { \
00633 BSEARCH_CHECK(conv(low)); \
00634 if (!smaller) return Qnil; \
00635 } \
00636 if (!satisfied) return Qnil; \
00637 return conv(low); \
00638 } while (0)
00639
00640
00641 beg = RANGE_BEG(range);
00642 end = RANGE_END(range);
00643
00644 if (FIXNUM_P(beg) && FIXNUM_P(end)) {
00645 long low = FIX2LONG(beg);
00646 long high = FIX2LONG(end);
00647 long mid, org_high;
00648 BSEARCH(INT2FIX);
00649 }
00650 #if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
00651 else if (RB_TYPE_P(beg, T_FLOAT) || RB_TYPE_P(end, T_FLOAT)) {
00652 int64_t low = double_as_int64(RFLOAT_VALUE(rb_Float(beg)));
00653 int64_t high = double_as_int64(RFLOAT_VALUE(rb_Float(end)));
00654 int64_t mid, org_high;
00655 BSEARCH(int64_as_double_to_num);
00656 }
00657 #endif
00658 else if (is_integer_p(beg) && is_integer_p(end)) {
00659 VALUE low = rb_to_int(beg);
00660 VALUE high = rb_to_int(end);
00661 VALUE mid, org_high;
00662 RETURN_ENUMERATOR(range, 0, 0);
00663 if (EXCL(range)) high = rb_funcall(high, '-', 1, INT2FIX(1));
00664 org_high = high;
00665
00666 while (rb_cmpint(rb_funcall(low, id_cmp, 1, high), low, high) < 0) {
00667 mid = rb_funcall(rb_funcall(high, '+', 1, low), id_div, 1, INT2FIX(2));
00668 BSEARCH_CHECK(mid);
00669 if (smaller) {
00670 high = mid;
00671 }
00672 else {
00673 low = rb_funcall(mid, '+', 1, INT2FIX(1));
00674 }
00675 }
00676 if (rb_equal(low, org_high)) {
00677 BSEARCH_CHECK(low);
00678 if (!smaller) return Qnil;
00679 }
00680 if (!satisfied) return Qnil;
00681 return low;
00682 }
00683 else {
00684 rb_raise(rb_eTypeError, "can't do binary search for %s", rb_obj_classname(beg));
00685 }
00686 return range;
00687 }
00688
00689 static VALUE
00690 each_i(RB_BLOCK_CALL_FUNC_ARGLIST(v, arg))
00691 {
00692 rb_yield(v);
00693 return Qnil;
00694 }
00695
00696 static VALUE
00697 sym_each_i(RB_BLOCK_CALL_FUNC_ARGLIST(v, arg))
00698 {
00699 rb_yield(rb_str_intern(v));
00700 return Qnil;
00701 }
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715 static VALUE
00716 range_size(VALUE range)
00717 {
00718 VALUE b = RANGE_BEG(range), e = RANGE_END(range);
00719 if (rb_obj_is_kind_of(b, rb_cNumeric) && rb_obj_is_kind_of(e, rb_cNumeric)) {
00720 return ruby_num_interval_step_size(b, e, INT2FIX(1), EXCL(range));
00721 }
00722 return Qnil;
00723 }
00724
00725 static VALUE
00726 range_enum_size(VALUE range, VALUE args, VALUE eobj)
00727 {
00728 return range_size(range);
00729 }
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752 static VALUE
00753 range_each(VALUE range)
00754 {
00755 VALUE beg, end;
00756
00757 RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_size);
00758
00759 beg = RANGE_BEG(range);
00760 end = RANGE_END(range);
00761
00762 if (FIXNUM_P(beg) && FIXNUM_P(end)) {
00763 long lim = FIX2LONG(end);
00764 long i;
00765
00766 if (!EXCL(range))
00767 lim += 1;
00768 for (i = FIX2LONG(beg); i < lim; i++) {
00769 rb_yield(LONG2FIX(i));
00770 }
00771 }
00772 else if (SYMBOL_P(beg) && SYMBOL_P(end)) {
00773 VALUE args[2];
00774
00775 args[0] = rb_sym_to_s(end);
00776 args[1] = EXCL(range) ? Qtrue : Qfalse;
00777 rb_block_call(rb_sym_to_s(beg), rb_intern("upto"), 2, args, sym_each_i, 0);
00778 }
00779 else {
00780 VALUE tmp = rb_check_string_type(beg);
00781
00782 if (!NIL_P(tmp)) {
00783 VALUE args[2];
00784
00785 args[0] = end;
00786 args[1] = EXCL(range) ? Qtrue : Qfalse;
00787 rb_block_call(tmp, rb_intern("upto"), 2, args, each_i, 0);
00788 }
00789 else {
00790 if (!discrete_object_p(beg)) {
00791 rb_raise(rb_eTypeError, "can't iterate from %s",
00792 rb_obj_classname(beg));
00793 }
00794 range_each_func(range, each_i, 0);
00795 }
00796 }
00797 return range;
00798 }
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809 static VALUE
00810 range_begin(VALUE range)
00811 {
00812 return RANGE_BEG(range);
00813 }
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827 static VALUE
00828 range_end(VALUE range)
00829 {
00830 return RANGE_END(range);
00831 }
00832
00833
00834 static VALUE
00835 first_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, cbarg))
00836 {
00837 VALUE *ary = (VALUE *)cbarg;
00838 long n = NUM2LONG(ary[0]);
00839
00840 if (n <= 0) {
00841 rb_iter_break();
00842 }
00843 rb_ary_push(ary[1], i);
00844 n--;
00845 ary[0] = INT2NUM(n);
00846 return Qnil;
00847 }
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861 static VALUE
00862 range_first(int argc, VALUE *argv, VALUE range)
00863 {
00864 VALUE n, ary[2];
00865
00866 if (argc == 0) return RANGE_BEG(range);
00867
00868 rb_scan_args(argc, argv, "1", &n);
00869 ary[0] = n;
00870 ary[1] = rb_ary_new2(NUM2LONG(n));
00871 rb_block_call(range, idEach, 0, 0, first_i, (VALUE)ary);
00872
00873 return ary[1];
00874 }
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894 static VALUE
00895 range_last(int argc, VALUE *argv, VALUE range)
00896 {
00897 if (argc == 0) return RANGE_END(range);
00898 return rb_ary_last(argc, argv, rb_Array(range));
00899 }
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917 static VALUE
00918 range_min(VALUE range)
00919 {
00920 if (rb_block_given_p()) {
00921 return rb_call_super(0, 0);
00922 }
00923 else {
00924 VALUE b = RANGE_BEG(range);
00925 VALUE e = RANGE_END(range);
00926 int c = rb_cmpint(rb_funcall(b, id_cmp, 1, e), b, e);
00927
00928 if (c > 0 || (c == 0 && EXCL(range)))
00929 return Qnil;
00930 return b;
00931 }
00932 }
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948 static VALUE
00949 range_max(VALUE range)
00950 {
00951 VALUE e = RANGE_END(range);
00952 int nm = FIXNUM_P(e) || rb_obj_is_kind_of(e, rb_cNumeric);
00953
00954 if (rb_block_given_p() || (EXCL(range) && !nm)) {
00955 return rb_call_super(0, 0);
00956 }
00957 else {
00958 VALUE b = RANGE_BEG(range);
00959 int c = rb_cmpint(rb_funcall(b, id_cmp, 1, e), b, e);
00960
00961 if (c > 0)
00962 return Qnil;
00963 if (EXCL(range)) {
00964 if (!FIXNUM_P(e) && !rb_obj_is_kind_of(e, rb_cInteger)) {
00965 rb_raise(rb_eTypeError, "cannot exclude non Integer end value");
00966 }
00967 if (c == 0) return Qnil;
00968 if (!FIXNUM_P(b) && !rb_obj_is_kind_of(b,rb_cInteger)) {
00969 rb_raise(rb_eTypeError, "cannot exclude end value with non Integer begin value");
00970 }
00971 if (FIXNUM_P(e)) {
00972 return LONG2NUM(FIX2LONG(e) - 1);
00973 }
00974 return rb_funcall(e, '-', 1, INT2FIX(1));
00975 }
00976 return e;
00977 }
00978 }
00979
00980 int
00981 rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
00982 {
00983 VALUE b, e;
00984 int excl;
00985
00986 if (rb_obj_is_kind_of(range, rb_cRange)) {
00987 b = RANGE_BEG(range);
00988 e = RANGE_END(range);
00989 excl = EXCL(range);
00990 }
00991 else {
00992 if (!rb_respond_to(range, id_beg)) return (int)Qfalse;
00993 if (!rb_respond_to(range, id_end)) return (int)Qfalse;
00994 b = rb_funcall(range, id_beg, 0);
00995 e = rb_funcall(range, id_end, 0);
00996 excl = RTEST(rb_funcall(range, rb_intern("exclude_end?"), 0));
00997 }
00998 *begp = b;
00999 *endp = e;
01000 *exclp = excl;
01001 return (int)Qtrue;
01002 }
01003
01004 VALUE
01005 rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
01006 {
01007 long beg, end, origbeg, origend;
01008 VALUE b, e;
01009 int excl;
01010
01011 if (!rb_range_values(range, &b, &e, &excl))
01012 return Qfalse;
01013 beg = NUM2LONG(b);
01014 end = NUM2LONG(e);
01015 origbeg = beg;
01016 origend = end;
01017 if (beg < 0) {
01018 beg += len;
01019 if (beg < 0)
01020 goto out_of_range;
01021 }
01022 if (end < 0)
01023 end += len;
01024 if (!excl)
01025 end++;
01026 if (err == 0 || err == 2) {
01027 if (beg > len)
01028 goto out_of_range;
01029 if (end > len)
01030 end = len;
01031 }
01032 len = end - beg;
01033 if (len < 0)
01034 len = 0;
01035
01036 *begp = beg;
01037 *lenp = len;
01038 return Qtrue;
01039
01040 out_of_range:
01041 if (err) {
01042 rb_raise(rb_eRangeError, "%ld..%s%ld out of range",
01043 origbeg, excl ? "." : "", origend);
01044 }
01045 return Qnil;
01046 }
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056 static VALUE
01057 range_to_s(VALUE range)
01058 {
01059 VALUE str, str2;
01060
01061 str = rb_obj_as_string(RANGE_BEG(range));
01062 str2 = rb_obj_as_string(RANGE_END(range));
01063 str = rb_str_dup(str);
01064 rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
01065 rb_str_append(str, str2);
01066 OBJ_INFECT(str, str2);
01067
01068 return str;
01069 }
01070
01071 static VALUE
01072 inspect_range(VALUE range, VALUE dummy, int recur)
01073 {
01074 VALUE str, str2;
01075
01076 if (recur) {
01077 return rb_str_new2(EXCL(range) ? "(... ... ...)" : "(... .. ...)");
01078 }
01079 str = rb_inspect(RANGE_BEG(range));
01080 str2 = rb_inspect(RANGE_END(range));
01081 str = rb_str_dup(str);
01082 rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
01083 rb_str_append(str, str2);
01084 OBJ_INFECT(str, str2);
01085
01086 return str;
01087 }
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099 static VALUE
01100 range_inspect(VALUE range)
01101 {
01102 return rb_exec_recursive(inspect_range, range, 0);
01103 }
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124 static VALUE
01125 range_eqq(VALUE range, VALUE val)
01126 {
01127 return rb_funcall(range, rb_intern("include?"), 1, val);
01128 }
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145 static VALUE
01146 range_include(VALUE range, VALUE val)
01147 {
01148 VALUE beg = RANGE_BEG(range);
01149 VALUE end = RANGE_END(range);
01150 int nv = FIXNUM_P(beg) || FIXNUM_P(end) ||
01151 rb_obj_is_kind_of(beg, rb_cNumeric) ||
01152 rb_obj_is_kind_of(end, rb_cNumeric);
01153
01154 if (nv ||
01155 !NIL_P(rb_check_to_integer(beg, "to_int")) ||
01156 !NIL_P(rb_check_to_integer(end, "to_int"))) {
01157 if (r_le(beg, val)) {
01158 if (EXCL(range)) {
01159 if (r_lt(val, end))
01160 return Qtrue;
01161 }
01162 else {
01163 if (r_le(val, end))
01164 return Qtrue;
01165 }
01166 }
01167 return Qfalse;
01168 }
01169 else if (RB_TYPE_P(beg, T_STRING) && RB_TYPE_P(end, T_STRING) &&
01170 RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) {
01171 if (NIL_P(val)) return Qfalse;
01172 if (RB_TYPE_P(val, T_STRING)) {
01173 if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1)
01174 return Qfalse;
01175 else {
01176 char b = RSTRING_PTR(beg)[0];
01177 char e = RSTRING_PTR(end)[0];
01178 char v = RSTRING_PTR(val)[0];
01179
01180 if (ISASCII(b) && ISASCII(e) && ISASCII(v)) {
01181 if (b <= v && v < e) return Qtrue;
01182 if (!EXCL(range) && v == e) return Qtrue;
01183 return Qfalse;
01184 }
01185 }
01186 }
01187 }
01188
01189 return rb_call_super(1, &val);
01190 }
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208 static VALUE
01209 range_cover(VALUE range, VALUE val)
01210 {
01211 VALUE beg, end;
01212
01213 beg = RANGE_BEG(range);
01214 end = RANGE_END(range);
01215 if (r_le(beg, val)) {
01216 if (EXCL(range)) {
01217 if (r_lt(val, end))
01218 return Qtrue;
01219 }
01220 else {
01221 if (r_le(val, end))
01222 return Qtrue;
01223 }
01224 }
01225 return Qfalse;
01226 }
01227
01228 static VALUE
01229 range_dumper(VALUE range)
01230 {
01231 VALUE v;
01232 NEWOBJ_OF(m, struct RObject, rb_cObject, T_OBJECT | (RGENGC_WB_PROTECTED_OBJECT ? FL_WB_PROTECTED : 1));
01233
01234 v = (VALUE)m;
01235
01236 rb_ivar_set(v, id_excl, RANGE_EXCL(range));
01237 rb_ivar_set(v, id_beg, RANGE_BEG(range));
01238 rb_ivar_set(v, id_end, RANGE_END(range));
01239 return v;
01240 }
01241
01242 static VALUE
01243 range_loader(VALUE range, VALUE obj)
01244 {
01245 if (!RB_TYPE_P(obj, T_OBJECT) || RBASIC(obj)->klass != rb_cObject) {
01246 rb_raise(rb_eTypeError, "not a dumped range object");
01247 }
01248
01249 range_modify(range);
01250 RANGE_SET_BEG(range, rb_ivar_get(obj, id_beg));
01251 RANGE_SET_END(range, rb_ivar_get(obj, id_end));
01252 RANGE_SET_EXCL(range, rb_ivar_get(obj, id_excl));
01253 return range;
01254 }
01255
01256 static VALUE
01257 range_alloc(VALUE klass)
01258 {
01259
01260
01261 return rb_struct_alloc_noinit(klass);
01262 }
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
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 void
01322 Init_Range(void)
01323 {
01324 #undef rb_intern
01325 #define rb_intern(str) rb_intern_const(str)
01326
01327 id_cmp = rb_intern("<=>");
01328 id_succ = rb_intern("succ");
01329 id_beg = rb_intern("begin");
01330 id_end = rb_intern("end");
01331 id_excl = rb_intern("excl");
01332 id_integer_p = rb_intern("integer?");
01333 id_div = rb_intern("div");
01334
01335 rb_cRange = rb_struct_define_without_accessor(
01336 "Range", rb_cObject, range_alloc,
01337 "begin", "end", "excl", NULL);
01338
01339 rb_include_module(rb_cRange, rb_mEnumerable);
01340 rb_marshal_define_compat(rb_cRange, rb_cObject, range_dumper, range_loader);
01341 rb_define_method(rb_cRange, "initialize", range_initialize, -1);
01342 rb_define_method(rb_cRange, "initialize_copy", range_initialize_copy, 1);
01343 rb_define_method(rb_cRange, "==", range_eq, 1);
01344 rb_define_method(rb_cRange, "===", range_eqq, 1);
01345 rb_define_method(rb_cRange, "eql?", range_eql, 1);
01346 rb_define_method(rb_cRange, "hash", range_hash, 0);
01347 rb_define_method(rb_cRange, "each", range_each, 0);
01348 rb_define_method(rb_cRange, "step", range_step, -1);
01349 rb_define_method(rb_cRange, "bsearch", range_bsearch, 0);
01350 rb_define_method(rb_cRange, "begin", range_begin, 0);
01351 rb_define_method(rb_cRange, "end", range_end, 0);
01352 rb_define_method(rb_cRange, "first", range_first, -1);
01353 rb_define_method(rb_cRange, "last", range_last, -1);
01354 rb_define_method(rb_cRange, "min", range_min, 0);
01355 rb_define_method(rb_cRange, "max", range_max, 0);
01356 rb_define_method(rb_cRange, "size", range_size, 0);
01357 rb_define_method(rb_cRange, "to_s", range_to_s, 0);
01358 rb_define_method(rb_cRange, "inspect", range_inspect, 0);
01359
01360 rb_define_method(rb_cRange, "exclude_end?", range_exclude_end_p, 0);
01361
01362 rb_define_method(rb_cRange, "member?", range_include, 1);
01363 rb_define_method(rb_cRange, "include?", range_include, 1);
01364 rb_define_method(rb_cRange, "cover?", range_cover, 1);
01365 }
01366