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