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