00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "ruby.h"
00014
00015 VALUE rb_cRange;
00016 static ID id_cmp, id_succ, id_beg, id_end, id_excl;
00017
00018 #define EXCL(r) RTEST(rb_ivar_get((r), id_excl))
00019 #define SET_EXCL(r,v) rb_ivar_set((r), id_excl, (v) ? Qtrue : Qfalse)
00020
00021 static VALUE
00022 range_failed()
00023 {
00024 rb_raise(rb_eArgError, "bad value for range");
00025 return Qnil;
00026 }
00027
00028 static VALUE
00029 range_check(args)
00030 VALUE *args;
00031 {
00032 return rb_funcall(args[0], id_cmp, 1, args[1]);
00033 }
00034
00035 static void
00036 range_init(range, beg, end, exclude_end)
00037 VALUE range, beg, end;
00038 int exclude_end;
00039 {
00040 VALUE args[2];
00041
00042 args[0] = beg;
00043 args[1] = end;
00044
00045 if (!FIXNUM_P(beg) || !FIXNUM_P(end)) {
00046 VALUE v;
00047
00048 v = rb_rescue(range_check, (VALUE)args, range_failed, 0);
00049 if (NIL_P(v)) range_failed();
00050 }
00051
00052 SET_EXCL(range, exclude_end);
00053 rb_ivar_set(range, id_beg, beg);
00054 rb_ivar_set(range, id_end, end);
00055 }
00056
00057 VALUE
00058 rb_range_new(beg, end, exclude_end)
00059 VALUE beg, end;
00060 int exclude_end;
00061 {
00062 VALUE range = rb_obj_alloc(rb_cRange);
00063
00064 range_init(range, beg, end, exclude_end);
00065 return range;
00066 }
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 static VALUE
00078 range_initialize(argc, argv, range)
00079 int argc;
00080 VALUE *argv;
00081 VALUE range;
00082 {
00083 VALUE beg, end, flags;
00084
00085 rb_scan_args(argc, argv, "21", &beg, &end, &flags);
00086
00087 if (rb_ivar_defined(range, id_beg)) {
00088 rb_name_error(rb_intern("initialize"), "`initialize' called twice");
00089 }
00090 range_init(range, beg, end, RTEST(flags));
00091 return Qnil;
00092 }
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 static VALUE
00103 range_exclude_end_p(range)
00104 VALUE range;
00105 {
00106 return EXCL(range) ? Qtrue : Qfalse;
00107 }
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 static VALUE
00125 range_eq(range, obj)
00126 VALUE range, obj;
00127 {
00128 if (range == obj) return Qtrue;
00129 if (!rb_obj_is_instance_of(obj, rb_obj_class(range)))
00130 return Qfalse;
00131
00132 if (!rb_equal(rb_ivar_get(range, id_beg), rb_ivar_get(obj, id_beg)))
00133 return Qfalse;
00134 if (!rb_equal(rb_ivar_get(range, id_end), rb_ivar_get(obj, id_end)))
00135 return Qfalse;
00136
00137 if (EXCL(range) != EXCL(obj)) return Qfalse;
00138
00139 return Qtrue;
00140 }
00141
00142 static int
00143 r_lt(a, b)
00144 VALUE a, b;
00145 {
00146 VALUE r = rb_funcall(a, id_cmp, 1, b);
00147
00148 if (NIL_P(r)) return Qfalse;
00149 if (rb_cmpint(r, a, b) < 0) return Qtrue;
00150 return Qfalse;
00151 }
00152
00153 static int
00154 r_le(a, b)
00155 VALUE a, b;
00156 {
00157 int c;
00158 VALUE r = rb_funcall(a, id_cmp, 1, b);
00159
00160 if (NIL_P(r)) return Qfalse;
00161 c = rb_cmpint(r, a, b);
00162 if (c == 0) return INT2FIX(0);
00163 if (c < 0) return Qtrue;
00164 return Qfalse;
00165 }
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 static VALUE
00183 range_eql(range, obj)
00184 VALUE range, obj;
00185 {
00186 if (range == obj) return Qtrue;
00187 if (!rb_obj_is_instance_of(obj, rb_obj_class(range)))
00188 return Qfalse;
00189
00190 if (!rb_eql(rb_ivar_get(range, id_beg), rb_ivar_get(obj, id_beg)))
00191 return Qfalse;
00192 if (!rb_eql(rb_ivar_get(range, id_end), rb_ivar_get(obj, id_end)))
00193 return Qfalse;
00194
00195 if (EXCL(range) != EXCL(obj)) return Qfalse;
00196
00197 return Qtrue;
00198 }
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209 static VALUE
00210 range_hash(range)
00211 VALUE range;
00212 {
00213 long hash = EXCL(range);
00214 VALUE v;
00215
00216 v = rb_hash(rb_ivar_get(range, id_beg));
00217 hash ^= v << 1;
00218 v = rb_hash(rb_ivar_get(range, id_end));
00219 hash ^= v << 9;
00220 hash ^= EXCL(range) << 24;
00221
00222 return LONG2FIX(hash);
00223 }
00224
00225 static VALUE
00226 str_step(args)
00227 VALUE *args;
00228 {
00229 return rb_str_upto(args[0], args[1], EXCL(args[2]));
00230 }
00231
00232 static void
00233 range_each_func(range, func, v, e, arg)
00234 VALUE range;
00235 void (*func) (VALUE, void*);
00236 VALUE v, e;
00237 void *arg;
00238 {
00239 int c;
00240
00241 if (EXCL(range)) {
00242 while (r_lt(v, e)) {
00243 (*func)(v, arg);
00244 v = rb_funcall(v, id_succ, 0, 0);
00245 }
00246 }
00247 else {
00248 while (RTEST(c = r_le(v, e))) {
00249 (*func)(v, arg);
00250 if (c == INT2FIX(0)) break;
00251 v = rb_funcall(v, id_succ, 0, 0);
00252 }
00253 }
00254 }
00255
00256 static VALUE
00257 step_i(i, iter)
00258 VALUE i;
00259 long *iter;
00260 {
00261 iter[0]--;
00262 if (iter[0] == 0) {
00263 rb_yield(i);
00264 iter[0] = iter[1];
00265 }
00266 return Qnil;
00267 }
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297 static VALUE
00298 range_step(argc, argv, range)
00299 int argc;
00300 VALUE *argv;
00301 VALUE range;
00302 {
00303 VALUE b, e, step;
00304 long unit;
00305
00306 b = rb_ivar_get(range, id_beg);
00307 e = rb_ivar_get(range, id_end);
00308 if (rb_scan_args(argc, argv, "01", &step) == 0) {
00309 step = INT2FIX(1);
00310 }
00311
00312 unit = NUM2LONG(step);
00313 if (unit < 0) {
00314 rb_raise(rb_eArgError, "step can't be negative");
00315 }
00316 if (FIXNUM_P(b) && FIXNUM_P(e)) {
00317 long end = FIX2LONG(e);
00318 long i;
00319
00320 if (unit == 0) rb_raise(rb_eArgError, "step can't be 0");
00321 if (!EXCL(range)) end += 1;
00322 for (i=FIX2LONG(b); i<end; i+=unit) {
00323 rb_yield(LONG2NUM(i));
00324 }
00325 }
00326 else {
00327 VALUE tmp = rb_check_string_type(b);
00328
00329 if (!NIL_P(tmp)) {
00330 VALUE args[5];
00331 long iter[2];
00332
00333 b = tmp;
00334 if (unit == 0) rb_raise(rb_eArgError, "step can't be 0");
00335 args[0] = b; args[1] = e; args[2] = range;
00336 iter[0] = 1; iter[1] = unit;
00337 rb_iterate((VALUE(*)(VALUE))str_step, (VALUE)args, step_i,
00338 (VALUE)iter);
00339 }
00340 else if (rb_obj_is_kind_of(b, rb_cNumeric)) {
00341 ID c = rb_intern(EXCL(range) ? "<" : "<=");
00342
00343 if (rb_equal(step, INT2FIX(0))) rb_raise(rb_eArgError, "step can't be 0");
00344 while (RTEST(rb_funcall(b, c, 1, e))) {
00345 rb_yield(b);
00346 b = rb_funcall(b, '+', 1, step);
00347 }
00348 }
00349 else {
00350 long args[2];
00351
00352 if (unit == 0) rb_raise(rb_eArgError, "step can't be 0");
00353 if (!rb_respond_to(b, id_succ)) {
00354 rb_raise(rb_eTypeError, "can't iterate from %s",
00355 rb_obj_classname(b));
00356 }
00357
00358 args[0] = 1;
00359 args[1] = unit;
00360 range_each_func(range, step_i, b, e, args);
00361 }
00362 }
00363 return range;
00364 }
00365
00366 static void
00367 each_i(v, arg)
00368 VALUE v;
00369 void *arg;
00370 {
00371 rb_yield(v);
00372 }
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392 static VALUE
00393 range_each(range)
00394 VALUE range;
00395 {
00396 VALUE beg, end;
00397
00398 beg = rb_ivar_get(range, id_beg);
00399 end = rb_ivar_get(range, id_end);
00400
00401 if (!rb_respond_to(beg, id_succ)) {
00402 rb_raise(rb_eTypeError, "can't iterate from %s",
00403 rb_obj_classname(beg));
00404 }
00405 if (FIXNUM_P(beg) && FIXNUM_P(end)) {
00406 long lim = FIX2LONG(end);
00407 long i;
00408
00409 if (!EXCL(range)) lim += 1;
00410 for (i=FIX2LONG(beg); i<lim; i++) {
00411 rb_yield(LONG2NUM(i));
00412 }
00413 }
00414 else if (TYPE(beg) == T_STRING) {
00415 VALUE args[5];
00416 long iter[2];
00417
00418 args[0] = beg; args[1] = end; args[2] = range;
00419 iter[0] = 1; iter[1] = 1;
00420 rb_iterate((VALUE(*)(VALUE))str_step, (VALUE)args, step_i,
00421 (VALUE)iter);
00422 }
00423 else {
00424 range_each_func(range, each_i, beg, end, NULL);
00425 }
00426 return range;
00427 }
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437 static VALUE
00438 range_first(range)
00439 VALUE range;
00440 {
00441 return rb_ivar_get(range, id_beg);
00442 }
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457 static VALUE
00458 range_last(range)
00459 VALUE range;
00460 {
00461 return rb_ivar_get(range, id_end);
00462 }
00463
00464 VALUE
00465 rb_range_beg_len(range, begp, lenp, len, err)
00466 VALUE range;
00467 long *begp, *lenp;
00468 long len;
00469 int err;
00470 {
00471 long beg, end, b, e;
00472
00473 if (!rb_obj_is_kind_of(range, rb_cRange)) return Qfalse;
00474
00475 beg = b = NUM2LONG(rb_ivar_get(range, id_beg));
00476 end = e = NUM2LONG(rb_ivar_get(range, id_end));
00477
00478 if (beg < 0) {
00479 beg += len;
00480 if (beg < 0) goto out_of_range;
00481 }
00482 if (err == 0 || err == 2) {
00483 if (beg > len) goto out_of_range;
00484 if (end > len) end = len;
00485 }
00486 if (end < 0) end += len;
00487 if (!EXCL(range)) end++;
00488 len = end - beg;
00489 if (len < 0) len = 0;
00490
00491 *begp = beg;
00492 *lenp = len;
00493 return Qtrue;
00494
00495 out_of_range:
00496 if (err) {
00497 rb_raise(rb_eRangeError, "%ld..%s%ld out of range",
00498 b, EXCL(range)? "." : "", e);
00499 }
00500 return Qnil;
00501 }
00502
00503
00504
00505
00506
00507
00508
00509
00510 static VALUE
00511 range_to_s(range)
00512 VALUE range;
00513 {
00514 VALUE str, str2;
00515
00516 str = rb_obj_as_string(rb_ivar_get(range, id_beg));
00517 str2 = rb_obj_as_string(rb_ivar_get(range, id_end));
00518 str = rb_str_dup(str);
00519 rb_str_cat(str, "...", EXCL(range)?3:2);
00520 rb_str_append(str, str2);
00521 OBJ_INFECT(str, str2);
00522
00523 return str;
00524 }
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536 static VALUE
00537 range_inspect(range)
00538 VALUE range;
00539 {
00540 VALUE str, str2;
00541
00542 str = rb_inspect(rb_ivar_get(range, id_beg));
00543 str2 = rb_inspect(rb_ivar_get(range, id_end));
00544 str = rb_str_dup(str);
00545 rb_str_cat(str, "...", EXCL(range)?3:2);
00546 rb_str_append(str, str2);
00547 OBJ_INFECT(str, str2);
00548
00549 return str;
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 static VALUE
00575 range_include(range, val)
00576 VALUE range, val;
00577 {
00578 VALUE beg, end;
00579
00580 beg = rb_ivar_get(range, id_beg);
00581 end = rb_ivar_get(range, id_end);
00582 if (r_le(beg, val)) {
00583 if (EXCL(range)) {
00584 if (r_lt(val, end)) return Qtrue;
00585 }
00586 else {
00587 if (r_le(val, end)) return Qtrue;
00588 }
00589 }
00590 return Qfalse;
00591 }
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646 void
00647 Init_Range()
00648 {
00649 rb_cRange = rb_define_class("Range", rb_cObject);
00650 rb_include_module(rb_cRange, rb_mEnumerable);
00651 rb_define_method(rb_cRange, "initialize", range_initialize, -1);
00652 rb_define_method(rb_cRange, "==", range_eq, 1);
00653 rb_define_method(rb_cRange, "===", range_include, 1);
00654 rb_define_method(rb_cRange, "eql?", range_eql, 1);
00655 rb_define_method(rb_cRange, "hash", range_hash, 0);
00656 rb_define_method(rb_cRange, "each", range_each, 0);
00657 rb_define_method(rb_cRange, "step", range_step, -1);
00658 rb_define_method(rb_cRange, "first", range_first, 0);
00659 rb_define_method(rb_cRange, "last", range_last, 0);
00660 rb_define_method(rb_cRange, "begin", range_first, 0);
00661 rb_define_method(rb_cRange, "end", range_last, 0);
00662 rb_define_method(rb_cRange, "to_s", range_to_s, 0);
00663 rb_define_method(rb_cRange, "inspect", range_inspect, 0);
00664
00665 rb_define_method(rb_cRange, "exclude_end?", range_exclude_end_p, 0);
00666
00667 rb_define_method(rb_cRange, "member?", range_include, 1);
00668 rb_define_method(rb_cRange, "include?", range_include, 1);
00669
00670 id_cmp = rb_intern("<=>");
00671 id_succ = rb_intern("succ");
00672 id_beg = rb_intern("begin");
00673 id_end = rb_intern("end");
00674 id_excl = rb_intern("excl");
00675 }
00676