Ruby 1.9.3p327(2012-11-10revision37606)
|
00001 /********************************************************************** 00002 00003 range.c - 00004 00005 $Author: tarui $ 00006 created at: Thu Aug 19 17:46:47 JST 1993 00007 00008 Copyright (C) 1993-2007 Yukihiro Matsumoto 00009 00010 **********************************************************************/ 00011 00012 #include "ruby/ruby.h" 00013 #include "ruby/encoding.h" 00014 #include "internal.h" 00015 00016 VALUE rb_cRange; 00017 static ID id_cmp, id_succ, id_beg, id_end, id_excl; 00018 00019 #define RANGE_BEG(r) (RSTRUCT(r)->as.ary[0]) 00020 #define RANGE_END(r) (RSTRUCT(r)->as.ary[1]) 00021 #define RANGE_EXCL(r) (RSTRUCT(r)->as.ary[2]) 00022 00023 #define EXCL(r) RTEST(RANGE_EXCL(r)) 00024 #define SET_EXCL(r,v) (RSTRUCT(r)->as.ary[2] = (v) ? Qtrue : Qfalse) 00025 00026 static VALUE 00027 range_failed(void) 00028 { 00029 rb_raise(rb_eArgError, "bad value for range"); 00030 return Qnil; /* dummy */ 00031 } 00032 00033 static VALUE 00034 range_check(VALUE *args) 00035 { 00036 return rb_funcall(args[0], id_cmp, 1, args[1]); 00037 } 00038 00039 static void 00040 range_init(VALUE range, VALUE beg, VALUE end, int exclude_end) 00041 { 00042 VALUE args[2]; 00043 00044 args[0] = beg; 00045 args[1] = end; 00046 00047 if (!FIXNUM_P(beg) || !FIXNUM_P(end)) { 00048 VALUE v; 00049 00050 v = rb_rescue(range_check, (VALUE)args, range_failed, 0); 00051 if (NIL_P(v)) 00052 range_failed(); 00053 } 00054 00055 SET_EXCL(range, exclude_end); 00056 RSTRUCT(range)->as.ary[0] = beg; 00057 RSTRUCT(range)->as.ary[1] = end; 00058 } 00059 00060 VALUE 00061 rb_range_new(VALUE beg, VALUE end, 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 * call-seq: 00071 * Range.new(start, end, exclusive=false) -> range 00072 * 00073 * Constructs a range using the given <i>start</i> and <i>end</i>. If the third 00074 * parameter is omitted or is <code>false</code>, the <i>range</i> will include 00075 * the end object; otherwise, it will be excluded. 00076 */ 00077 00078 static VALUE 00079 range_initialize(int argc, VALUE *argv, VALUE range) 00080 { 00081 VALUE beg, end, flags; 00082 00083 rb_scan_args(argc, argv, "21", &beg, &end, &flags); 00084 /* Ranges are immutable, so that they should be initialized only once. */ 00085 if (RANGE_EXCL(range) != Qnil) { 00086 rb_name_error(rb_intern("initialize"), "`initialize' called twice"); 00087 } 00088 range_init(range, beg, end, RTEST(flags)); 00089 return Qnil; 00090 } 00091 00092 #define range_initialize_copy rb_struct_init_copy /* :nodoc: */ 00093 00094 /* 00095 * call-seq: 00096 * rng.exclude_end? -> true or false 00097 * 00098 * Returns <code>true</code> if <i>rng</i> excludes its end value. 00099 */ 00100 00101 static VALUE 00102 range_exclude_end_p(VALUE range) 00103 { 00104 return EXCL(range) ? Qtrue : Qfalse; 00105 } 00106 00107 static VALUE 00108 recursive_equal(VALUE range, VALUE obj, int recur) 00109 { 00110 if (recur) return Qtrue; /* Subtle! */ 00111 if (!rb_equal(RANGE_BEG(range), RANGE_BEG(obj))) 00112 return Qfalse; 00113 if (!rb_equal(RANGE_END(range), RANGE_END(obj))) 00114 return Qfalse; 00115 00116 if (EXCL(range) != EXCL(obj)) 00117 return Qfalse; 00118 return Qtrue; 00119 } 00120 00121 00122 /* 00123 * call-seq: 00124 * rng == obj -> true or false 00125 * 00126 * Returns <code>true</code> only if <i>obj</i> is a Range, has equivalent 00127 * beginning and end items (by comparing them with <code>==</code>), and has 00128 * the same <code>exclude_end?</code> setting as <i>rng</i>. 00129 * 00130 * (0..2) == (0..2) #=> true 00131 * (0..2) == Range.new(0,2) #=> true 00132 * (0..2) == (0...2) #=> false 00133 * 00134 */ 00135 00136 static VALUE 00137 range_eq(VALUE range, VALUE obj) 00138 { 00139 if (range == obj) 00140 return Qtrue; 00141 if (!rb_obj_is_kind_of(obj, rb_cRange)) 00142 return Qfalse; 00143 00144 return rb_exec_recursive_paired(recursive_equal, range, obj, obj); 00145 } 00146 00147 static int 00148 r_lt(VALUE a, VALUE b) 00149 { 00150 VALUE r = rb_funcall(a, id_cmp, 1, b); 00151 00152 if (NIL_P(r)) 00153 return (int)Qfalse; 00154 if (rb_cmpint(r, a, b) < 0) 00155 return (int)Qtrue; 00156 return (int)Qfalse; 00157 } 00158 00159 static int 00160 r_le(VALUE a, VALUE b) 00161 { 00162 int c; 00163 VALUE r = rb_funcall(a, id_cmp, 1, b); 00164 00165 if (NIL_P(r)) 00166 return (int)Qfalse; 00167 c = rb_cmpint(r, a, b); 00168 if (c == 0) 00169 return (int)INT2FIX(0); 00170 if (c < 0) 00171 return (int)Qtrue; 00172 return (int)Qfalse; 00173 } 00174 00175 00176 static VALUE 00177 recursive_eql(VALUE range, VALUE obj, int recur) 00178 { 00179 if (recur) return Qtrue; /* Subtle! */ 00180 if (!rb_eql(RANGE_BEG(range), RANGE_BEG(obj))) 00181 return Qfalse; 00182 if (!rb_eql(RANGE_END(range), RANGE_END(obj))) 00183 return Qfalse; 00184 00185 if (EXCL(range) != EXCL(obj)) 00186 return Qfalse; 00187 return Qtrue; 00188 } 00189 00190 /* 00191 * call-seq: 00192 * rng.eql?(obj) -> true or false 00193 * 00194 * Returns <code>true</code> only if <i>obj</i> is a Range, has equivalent 00195 * beginning and end items (by comparing them with #eql?), and has the same 00196 * #exclude_end? setting as <i>rng</i>. 00197 * 00198 * (0..2).eql?(0..2) #=> true 00199 * (0..2).eql?(Range.new(0,2)) #=> true 00200 * (0..2).eql?(0...2) #=> false 00201 * 00202 */ 00203 00204 static VALUE 00205 range_eql(VALUE range, VALUE obj) 00206 { 00207 if (range == obj) 00208 return Qtrue; 00209 if (!rb_obj_is_kind_of(obj, rb_cRange)) 00210 return Qfalse; 00211 return rb_exec_recursive_paired(recursive_eql, range, obj, obj); 00212 } 00213 00214 static VALUE 00215 recursive_hash(VALUE range, VALUE dummy, int recur) 00216 { 00217 st_index_t hash = EXCL(range); 00218 VALUE v; 00219 00220 hash = rb_hash_start(hash); 00221 if (!recur) { 00222 v = rb_hash(RANGE_BEG(range)); 00223 hash = rb_hash_uint(hash, NUM2LONG(v)); 00224 v = rb_hash(RANGE_END(range)); 00225 hash = rb_hash_uint(hash, NUM2LONG(v)); 00226 } 00227 hash = rb_hash_uint(hash, EXCL(range) << 24); 00228 hash = rb_hash_end(hash); 00229 00230 return LONG2FIX(hash); 00231 } 00232 00233 /* 00234 * call-seq: 00235 * rng.hash -> fixnum 00236 * 00237 * Generate a hash value such that two ranges with the same start and 00238 * end points, and the same value for the "exclude end" flag, generate 00239 * the same hash value. 00240 */ 00241 00242 static VALUE 00243 range_hash(VALUE range) 00244 { 00245 return rb_exec_recursive_outer(recursive_hash, range, 0); 00246 } 00247 00248 static void 00249 range_each_func(VALUE range, VALUE (*func) (VALUE, void *), void *arg) 00250 { 00251 int c; 00252 VALUE b = RANGE_BEG(range); 00253 VALUE e = RANGE_END(range); 00254 VALUE v = b; 00255 00256 if (EXCL(range)) { 00257 while (r_lt(v, e)) { 00258 (*func) (v, arg); 00259 v = rb_funcall(v, id_succ, 0, 0); 00260 } 00261 } 00262 else { 00263 while ((c = r_le(v, e)) != Qfalse) { 00264 (*func) (v, arg); 00265 if (c == (int)INT2FIX(0)) 00266 break; 00267 v = rb_funcall(v, id_succ, 0, 0); 00268 } 00269 } 00270 } 00271 00272 static VALUE 00273 sym_step_i(VALUE i, void *arg) 00274 { 00275 VALUE *iter = arg; 00276 00277 if (FIXNUM_P(iter[0])) { 00278 iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG; 00279 } 00280 else { 00281 iter[0] = rb_funcall(iter[0], '-', 1, INT2FIX(1)); 00282 } 00283 if (iter[0] == INT2FIX(0)) { 00284 rb_yield(rb_str_intern(i)); 00285 iter[0] = iter[1]; 00286 } 00287 return Qnil; 00288 } 00289 00290 static VALUE 00291 step_i(VALUE i, void *arg) 00292 { 00293 VALUE *iter = arg; 00294 00295 if (FIXNUM_P(iter[0])) { 00296 iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG; 00297 } 00298 else { 00299 iter[0] = rb_funcall(iter[0], '-', 1, INT2FIX(1)); 00300 } 00301 if (iter[0] == INT2FIX(0)) { 00302 rb_yield(i); 00303 iter[0] = iter[1]; 00304 } 00305 return Qnil; 00306 } 00307 00308 static int 00309 discrete_object_p(VALUE obj) 00310 { 00311 if (rb_obj_is_kind_of(obj, rb_cTime)) return FALSE; /* until Time#succ removed */ 00312 return rb_respond_to(obj, id_succ); 00313 } 00314 00315 00316 /* 00317 * call-seq: 00318 * rng.step(n=1) {| obj | block } -> rng 00319 * rng.step(n=1) -> an_enumerator 00320 * 00321 * Iterates over <i>rng</i>, passing each <i>n</i>th element to the block. If 00322 * the range contains numbers, <i>n</i> is added for each iteration. Otherwise 00323 * <code>step</code> invokes <code>succ</code> to iterate through range 00324 * elements. The following code uses class <code>Xs</code>, which is defined 00325 * in the class-level documentation. 00326 * 00327 * If no block is given, an enumerator is returned instead. 00328 * 00329 * range = Xs.new(1)..Xs.new(10) 00330 * range.step(2) {|x| puts x} 00331 * range.step(3) {|x| puts x} 00332 * 00333 * <em>produces:</em> 00334 * 00335 * 1 x 00336 * 3 xxx 00337 * 5 xxxxx 00338 * 7 xxxxxxx 00339 * 9 xxxxxxxxx 00340 * 1 x 00341 * 4 xxxx 00342 * 7 xxxxxxx 00343 * 10 xxxxxxxxxx 00344 */ 00345 00346 00347 static VALUE 00348 range_step(int argc, VALUE *argv, VALUE range) 00349 { 00350 VALUE b, e, step, tmp; 00351 00352 RETURN_ENUMERATOR(range, argc, argv); 00353 00354 b = RANGE_BEG(range); 00355 e = RANGE_END(range); 00356 if (argc == 0) { 00357 step = INT2FIX(1); 00358 } 00359 else { 00360 rb_scan_args(argc, argv, "01", &step); 00361 if (!rb_obj_is_kind_of(step, rb_cNumeric)) { 00362 step = rb_to_int(step); 00363 } 00364 if (rb_funcall(step, '<', 1, INT2FIX(0))) { 00365 rb_raise(rb_eArgError, "step can't be negative"); 00366 } 00367 else if (!rb_funcall(step, '>', 1, INT2FIX(0))) { 00368 rb_raise(rb_eArgError, "step can't be 0"); 00369 } 00370 } 00371 00372 if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */ 00373 long end = FIX2LONG(e); 00374 long i, unit = FIX2LONG(step); 00375 00376 if (!EXCL(range)) 00377 end += 1; 00378 i = FIX2LONG(b); 00379 while (i < end) { 00380 rb_yield(LONG2NUM(i)); 00381 if (i + unit < i) break; 00382 i += unit; 00383 } 00384 00385 } 00386 else if (SYMBOL_P(b) && SYMBOL_P(e)) { /* symbols are special */ 00387 VALUE args[2], iter[2]; 00388 00389 args[0] = rb_sym_to_s(e); 00390 args[1] = EXCL(range) ? Qtrue : Qfalse; 00391 iter[0] = INT2FIX(1); 00392 iter[1] = step; 00393 rb_block_call(rb_sym_to_s(b), rb_intern("upto"), 2, args, sym_step_i, (VALUE)iter); 00394 } 00395 else if (ruby_float_step(b, e, step, EXCL(range))) { 00396 /* done */ 00397 } 00398 else if (rb_obj_is_kind_of(b, rb_cNumeric) || 00399 !NIL_P(rb_check_to_integer(b, "to_int")) || 00400 !NIL_P(rb_check_to_integer(e, "to_int"))) { 00401 ID op = EXCL(range) ? '<' : rb_intern("<="); 00402 VALUE v = b; 00403 int i = 0; 00404 00405 while (RTEST(rb_funcall(v, op, 1, e))) { 00406 rb_yield(v); 00407 i++; 00408 v = rb_funcall(b, '+', 1, rb_funcall(INT2NUM(i), '*', 1, step)); 00409 } 00410 } 00411 else { 00412 tmp = rb_check_string_type(b); 00413 00414 if (!NIL_P(tmp)) { 00415 VALUE args[2], iter[2]; 00416 00417 b = tmp; 00418 args[0] = e; 00419 args[1] = EXCL(range) ? Qtrue : Qfalse; 00420 iter[0] = INT2FIX(1); 00421 iter[1] = step; 00422 rb_block_call(b, rb_intern("upto"), 2, args, step_i, (VALUE)iter); 00423 } 00424 else { 00425 VALUE args[2]; 00426 00427 if (!discrete_object_p(b)) { 00428 rb_raise(rb_eTypeError, "can't iterate from %s", 00429 rb_obj_classname(b)); 00430 } 00431 args[0] = INT2FIX(1); 00432 args[1] = step; 00433 range_each_func(range, step_i, args); 00434 } 00435 } 00436 return range; 00437 } 00438 00439 static VALUE 00440 each_i(VALUE v, void *arg) 00441 { 00442 rb_yield(v); 00443 return Qnil; 00444 } 00445 00446 static VALUE 00447 sym_each_i(VALUE v, void *arg) 00448 { 00449 rb_yield(rb_str_intern(v)); 00450 return Qnil; 00451 } 00452 00453 /* 00454 * call-seq: 00455 * rng.each {| i | block } -> rng 00456 * rng.each -> an_enumerator 00457 * 00458 * Iterates over the elements <i>rng</i>, passing each in turn to the 00459 * block. You can only iterate if the start object of the range 00460 * supports the +succ+ method (which means that you can't iterate over 00461 * ranges of +Float+ objects). 00462 * 00463 * If no block is given, an enumerator is returned instead. 00464 * 00465 * (10..15).each do |n| 00466 * print n, ' ' 00467 * end 00468 * 00469 * <em>produces:</em> 00470 * 00471 * 10 11 12 13 14 15 00472 */ 00473 00474 static VALUE 00475 range_each(VALUE range) 00476 { 00477 VALUE beg, end; 00478 00479 RETURN_ENUMERATOR(range, 0, 0); 00480 00481 beg = RANGE_BEG(range); 00482 end = RANGE_END(range); 00483 00484 if (FIXNUM_P(beg) && FIXNUM_P(end)) { /* fixnums are special */ 00485 long lim = FIX2LONG(end); 00486 long i; 00487 00488 if (!EXCL(range)) 00489 lim += 1; 00490 for (i = FIX2LONG(beg); i < lim; i++) { 00491 rb_yield(LONG2FIX(i)); 00492 } 00493 } 00494 else if (SYMBOL_P(beg) && SYMBOL_P(end)) { /* symbols are special */ 00495 VALUE args[2]; 00496 00497 args[0] = rb_sym_to_s(end); 00498 args[1] = EXCL(range) ? Qtrue : Qfalse; 00499 rb_block_call(rb_sym_to_s(beg), rb_intern("upto"), 2, args, sym_each_i, 0); 00500 } 00501 else { 00502 VALUE tmp = rb_check_string_type(beg); 00503 00504 if (!NIL_P(tmp)) { 00505 VALUE args[2]; 00506 00507 args[0] = end; 00508 args[1] = EXCL(range) ? Qtrue : Qfalse; 00509 rb_block_call(tmp, rb_intern("upto"), 2, args, rb_yield, 0); 00510 } 00511 else { 00512 if (!discrete_object_p(beg)) { 00513 rb_raise(rb_eTypeError, "can't iterate from %s", 00514 rb_obj_classname(beg)); 00515 } 00516 range_each_func(range, each_i, NULL); 00517 } 00518 } 00519 return range; 00520 } 00521 00522 /* 00523 * call-seq: 00524 * rng.begin -> obj 00525 * 00526 * Returns the first object in <i>rng</i>. 00527 */ 00528 00529 static VALUE 00530 range_begin(VALUE range) 00531 { 00532 return RANGE_BEG(range); 00533 } 00534 00535 00536 /* 00537 * call-seq: 00538 * rng.end -> obj 00539 * 00540 * Returns the object that defines the end of <i>rng</i>. 00541 * 00542 * (1..10).end #=> 10 00543 * (1...10).end #=> 10 00544 */ 00545 00546 00547 static VALUE 00548 range_end(VALUE range) 00549 { 00550 return RANGE_END(range); 00551 } 00552 00553 00554 static VALUE 00555 first_i(VALUE i, VALUE *ary) 00556 { 00557 long n = NUM2LONG(ary[0]); 00558 00559 if (n <= 0) { 00560 rb_iter_break(); 00561 } 00562 rb_ary_push(ary[1], i); 00563 n--; 00564 ary[0] = INT2NUM(n); 00565 return Qnil; 00566 } 00567 00568 /* 00569 * call-seq: 00570 * rng.first -> obj 00571 * rng.first(n) -> an_array 00572 * 00573 * Returns the first object in <i>rng</i>, or the first +n+ elements. 00574 */ 00575 00576 static VALUE 00577 range_first(int argc, VALUE *argv, VALUE range) 00578 { 00579 VALUE n, ary[2]; 00580 00581 if (argc == 0) return RANGE_BEG(range); 00582 00583 rb_scan_args(argc, argv, "1", &n); 00584 ary[0] = n; 00585 ary[1] = rb_ary_new2(NUM2LONG(n)); 00586 rb_block_call(range, rb_intern("each"), 0, 0, first_i, (VALUE)ary); 00587 00588 return ary[1]; 00589 } 00590 00591 00592 /* 00593 * call-seq: 00594 * rng.last -> obj 00595 * rng.last(n) -> an_array 00596 * 00597 * Returns the last object in <i>rng</i>, or the last +n+ elements. 00598 */ 00599 00600 static VALUE 00601 range_last(int argc, VALUE *argv, VALUE range) 00602 { 00603 if (argc == 0) return RANGE_END(range); 00604 return rb_ary_last(argc, argv, rb_Array(range)); 00605 } 00606 00607 00608 /* 00609 * call-seq: 00610 * rng.min -> obj 00611 * rng.min {| a,b | block } -> obj 00612 * 00613 * Returns the minimum value in <i>rng</i>. The second uses 00614 * the block to compare values. Returns nil if the first 00615 * value in range is larger than the last value. 00616 * 00617 */ 00618 00619 00620 static VALUE 00621 range_min(VALUE range) 00622 { 00623 if (rb_block_given_p()) { 00624 return rb_call_super(0, 0); 00625 } 00626 else { 00627 VALUE b = RANGE_BEG(range); 00628 VALUE e = RANGE_END(range); 00629 int c = rb_cmpint(rb_funcall(b, id_cmp, 1, e), b, e); 00630 00631 if (c > 0 || (c == 0 && EXCL(range))) 00632 return Qnil; 00633 return b; 00634 } 00635 } 00636 00637 /* 00638 * call-seq: 00639 * rng.max -> obj 00640 * rng.max {| a,b | block } -> obj 00641 * 00642 * Returns the maximum value in <i>rng</i>. The second uses 00643 * the block to compare values. Returns nil if the first 00644 * value in range is larger than the last value. 00645 * 00646 */ 00647 00648 static VALUE 00649 range_max(VALUE range) 00650 { 00651 VALUE e = RANGE_END(range); 00652 int nm = FIXNUM_P(e) || rb_obj_is_kind_of(e, rb_cNumeric); 00653 00654 if (rb_block_given_p() || (EXCL(range) && !nm)) { 00655 return rb_call_super(0, 0); 00656 } 00657 else { 00658 VALUE b = RANGE_BEG(range); 00659 int c = rb_cmpint(rb_funcall(b, id_cmp, 1, e), b, e); 00660 00661 if (c > 0) 00662 return Qnil; 00663 if (EXCL(range)) { 00664 if (!FIXNUM_P(e) && !rb_obj_is_kind_of(e, rb_cInteger)) { 00665 rb_raise(rb_eTypeError, "cannot exclude non Integer end value"); 00666 } 00667 if (c == 0) return Qnil; 00668 if (!FIXNUM_P(b) && !rb_obj_is_kind_of(b,rb_cInteger)) { 00669 rb_raise(rb_eTypeError, "cannot exclude end value with non Integer begin value"); 00670 } 00671 if (FIXNUM_P(e)) { 00672 return LONG2NUM(FIX2LONG(e) - 1); 00673 } 00674 return rb_funcall(e, '-', 1, INT2FIX(1)); 00675 } 00676 return e; 00677 } 00678 } 00679 00680 int 00681 rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp) 00682 { 00683 VALUE b, e; 00684 int excl; 00685 00686 if (rb_obj_is_kind_of(range, rb_cRange)) { 00687 b = RANGE_BEG(range); 00688 e = RANGE_END(range); 00689 excl = EXCL(range); 00690 } 00691 else { 00692 if (!rb_respond_to(range, id_beg)) return (int)Qfalse; 00693 if (!rb_respond_to(range, id_end)) return (int)Qfalse; 00694 b = rb_funcall(range, id_beg, 0); 00695 e = rb_funcall(range, id_end, 0); 00696 excl = RTEST(rb_funcall(range, rb_intern("exclude_end?"), 0)); 00697 } 00698 *begp = b; 00699 *endp = e; 00700 *exclp = excl; 00701 return (int)Qtrue; 00702 } 00703 00704 VALUE 00705 rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err) 00706 { 00707 long beg, end, origbeg, origend; 00708 VALUE b, e; 00709 int excl; 00710 00711 if (!rb_range_values(range, &b, &e, &excl)) 00712 return Qfalse; 00713 beg = NUM2LONG(b); 00714 end = NUM2LONG(e); 00715 origbeg = beg; 00716 origend = end; 00717 if (beg < 0) { 00718 beg += len; 00719 if (beg < 0) 00720 goto out_of_range; 00721 } 00722 if (err == 0 || err == 2) { 00723 if (beg > len) 00724 goto out_of_range; 00725 if (end > len) 00726 end = len; 00727 } 00728 if (end < 0) 00729 end += len; 00730 if (!excl) 00731 end++; /* include end point */ 00732 len = end - beg; 00733 if (len < 0) 00734 len = 0; 00735 00736 *begp = beg; 00737 *lenp = len; 00738 return Qtrue; 00739 00740 out_of_range: 00741 if (err) { 00742 rb_raise(rb_eRangeError, "%ld..%s%ld out of range", 00743 origbeg, excl ? "." : "", origend); 00744 } 00745 return Qnil; 00746 } 00747 00748 /* 00749 * call-seq: 00750 * rng.to_s -> string 00751 * 00752 * Convert this range object to a printable form. 00753 */ 00754 00755 static VALUE 00756 range_to_s(VALUE range) 00757 { 00758 VALUE str, str2; 00759 00760 str = rb_obj_as_string(RANGE_BEG(range)); 00761 str2 = rb_obj_as_string(RANGE_END(range)); 00762 str = rb_str_dup(str); 00763 rb_str_cat(str, "...", EXCL(range) ? 3 : 2); 00764 rb_str_append(str, str2); 00765 OBJ_INFECT(str, str2); 00766 00767 return str; 00768 } 00769 00770 static VALUE 00771 inspect_range(VALUE range, VALUE dummy, int recur) 00772 { 00773 VALUE str, str2; 00774 00775 if (recur) { 00776 return rb_str_new2(EXCL(range) ? "(... ... ...)" : "(... .. ...)"); 00777 } 00778 str = rb_inspect(RANGE_BEG(range)); 00779 str2 = rb_inspect(RANGE_END(range)); 00780 str = rb_str_dup(str); 00781 rb_str_cat(str, "...", EXCL(range) ? 3 : 2); 00782 rb_str_append(str, str2); 00783 OBJ_INFECT(str, str2); 00784 00785 return str; 00786 } 00787 00788 /* 00789 * call-seq: 00790 * rng.inspect -> string 00791 * 00792 * Convert this range object to a printable form (using 00793 * <code>inspect</code> to convert the start and end 00794 * objects). 00795 */ 00796 00797 00798 static VALUE 00799 range_inspect(VALUE range) 00800 { 00801 return rb_exec_recursive(inspect_range, range, 0); 00802 } 00803 00804 /* 00805 * call-seq: 00806 * rng === obj -> true or false 00807 * 00808 * Returns <code>true</code> if <i>obj</i> is an element of 00809 * <i>rng</i>, <code>false</code> otherwise. Conveniently, 00810 * <code>===</code> is the comparison operator used by 00811 * <code>case</code> statements. 00812 * 00813 * case 79 00814 * when 1..50 then print "low\n" 00815 * when 51..75 then print "medium\n" 00816 * when 76..100 then print "high\n" 00817 * end 00818 * 00819 * <em>produces:</em> 00820 * 00821 * high 00822 */ 00823 00824 static VALUE 00825 range_eqq(VALUE range, VALUE val) 00826 { 00827 return rb_funcall(range, rb_intern("include?"), 1, val); 00828 } 00829 00830 00831 /* 00832 * call-seq: 00833 * rng.member?(val) -> true or false 00834 * rng.include?(val) -> true or false 00835 * 00836 * Returns <code>true</code> if <i>obj</i> is an element of 00837 * <i>rng</i>, <code>false</code> otherwise. If beg and end are 00838 * numeric, comparison is done according magnitude of values. 00839 * 00840 * ("a".."z").include?("g") # -> true 00841 * ("a".."z").include?("A") # -> false 00842 */ 00843 00844 static VALUE 00845 range_include(VALUE range, VALUE val) 00846 { 00847 VALUE beg = RANGE_BEG(range); 00848 VALUE end = RANGE_END(range); 00849 int nv = FIXNUM_P(beg) || FIXNUM_P(end) || 00850 rb_obj_is_kind_of(beg, rb_cNumeric) || 00851 rb_obj_is_kind_of(end, rb_cNumeric); 00852 00853 if (nv || 00854 !NIL_P(rb_check_to_integer(beg, "to_int")) || 00855 !NIL_P(rb_check_to_integer(end, "to_int"))) { 00856 if (r_le(beg, val)) { 00857 if (EXCL(range)) { 00858 if (r_lt(val, end)) 00859 return Qtrue; 00860 } 00861 else { 00862 if (r_le(val, end)) 00863 return Qtrue; 00864 } 00865 } 00866 return Qfalse; 00867 } 00868 else if (TYPE(beg) == T_STRING && TYPE(end) == T_STRING && 00869 RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) { 00870 if (NIL_P(val)) return Qfalse; 00871 if (TYPE(val) == T_STRING) { 00872 if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1) 00873 return Qfalse; 00874 else { 00875 char b = RSTRING_PTR(beg)[0]; 00876 char e = RSTRING_PTR(end)[0]; 00877 char v = RSTRING_PTR(val)[0]; 00878 00879 if (ISASCII(b) && ISASCII(e) && ISASCII(v)) { 00880 if (b <= v && v < e) return Qtrue; 00881 if (!EXCL(range) && v == e) return Qtrue; 00882 return Qfalse; 00883 } 00884 } 00885 } 00886 } 00887 /* TODO: ruby_frame->this_func = rb_intern("include?"); */ 00888 return rb_call_super(1, &val); 00889 } 00890 00891 00892 /* 00893 * call-seq: 00894 * rng.cover?(val) -> true or false 00895 * 00896 * Returns <code>true</code> if <i>obj</i> is between beg and end, 00897 * i.e <code>beg <= obj <= end</code> (or <i>end</i> exclusive when 00898 * <code>exclude_end?</code> is true). 00899 * 00900 * ("a".."z").cover?("c") #=> true 00901 * ("a".."z").cover?("5") #=> false 00902 */ 00903 00904 static VALUE 00905 range_cover(VALUE range, VALUE val) 00906 { 00907 VALUE beg, end; 00908 00909 beg = RANGE_BEG(range); 00910 end = RANGE_END(range); 00911 if (r_le(beg, val)) { 00912 if (EXCL(range)) { 00913 if (r_lt(val, end)) 00914 return Qtrue; 00915 } 00916 else { 00917 if (r_le(val, end)) 00918 return Qtrue; 00919 } 00920 } 00921 return Qfalse; 00922 } 00923 00924 static VALUE 00925 range_dumper(VALUE range) 00926 { 00927 VALUE v; 00928 NEWOBJ(m, struct RObject); 00929 OBJSETUP(m, rb_cObject, T_OBJECT); 00930 00931 v = (VALUE)m; 00932 00933 rb_ivar_set(v, id_excl, RANGE_EXCL(range)); 00934 rb_ivar_set(v, id_beg, RANGE_BEG(range)); 00935 rb_ivar_set(v, id_end, RANGE_END(range)); 00936 return v; 00937 } 00938 00939 static VALUE 00940 range_loader(VALUE range, VALUE obj) 00941 { 00942 if (TYPE(obj) != T_OBJECT || RBASIC(obj)->klass != rb_cObject) { 00943 rb_raise(rb_eTypeError, "not a dumped range object"); 00944 } 00945 00946 RSTRUCT(range)->as.ary[0] = rb_ivar_get(obj, id_beg); 00947 RSTRUCT(range)->as.ary[1] = rb_ivar_get(obj, id_end); 00948 RSTRUCT(range)->as.ary[2] = rb_ivar_get(obj, id_excl); 00949 return range; 00950 } 00951 00952 static VALUE 00953 range_alloc(VALUE klass) 00954 { 00955 /* rb_struct_alloc_noinit itself should not be used because 00956 * rb_marshal_define_compat uses equality of allocaiton function */ 00957 return rb_struct_alloc_noinit(klass); 00958 } 00959 00960 /* A <code>Range</code> represents an interval---a set of values with a 00961 * start and an end. Ranges may be constructed using the 00962 * <em>s</em><code>..</code><em>e</em> and 00963 * <em>s</em><code>...</code><em>e</em> literals, or with 00964 * <code>Range::new</code>. Ranges constructed using <code>..</code> 00965 * run from the start to the end inclusively. Those created using 00966 * <code>...</code> exclude the end value. When used as an iterator, 00967 * ranges return each value in the sequence. 00968 * 00969 * (-1..-5).to_a #=> [] 00970 * (-5..-1).to_a #=> [-5, -4, -3, -2, -1] 00971 * ('a'..'e').to_a #=> ["a", "b", "c", "d", "e"] 00972 * ('a'...'e').to_a #=> ["a", "b", "c", "d"] 00973 * 00974 * Ranges can be constructed using objects of any type, as long as the 00975 * objects can be compared using their <code><=></code> operator and 00976 * they support the <code>succ</code> method to return the next object 00977 * in sequence. 00978 * 00979 * class Xs # represent a string of 'x's 00980 * include Comparable 00981 * attr :length 00982 * def initialize(n) 00983 * @length = n 00984 * end 00985 * def succ 00986 * Xs.new(@length + 1) 00987 * end 00988 * def <=>(other) 00989 * @length <=> other.length 00990 * end 00991 * def to_s 00992 * sprintf "%2d #{inspect}", @length 00993 * end 00994 * def inspect 00995 * 'x' * @length 00996 * end 00997 * end 00998 * 00999 * r = Xs.new(3)..Xs.new(6) #=> xxx..xxxxxx 01000 * r.to_a #=> [xxx, xxxx, xxxxx, xxxxxx] 01001 * r.member?(Xs.new(5)) #=> true 01002 * 01003 * In the previous code example, class <code>Xs</code> includes the 01004 * <code>Comparable</code> module. This is because 01005 * <code>Enumerable#member?</code> checks for equality using 01006 * <code>==</code>. Including <code>Comparable</code> ensures that the 01007 * <code>==</code> method is defined in terms of the <code><=></code> 01008 * method implemented in <code>Xs</code>. 01009 * 01010 */ 01011 01012 void 01013 Init_Range(void) 01014 { 01015 #undef rb_intern 01016 #define rb_intern(str) rb_intern_const(str) 01017 01018 id_cmp = rb_intern("<=>"); 01019 id_succ = rb_intern("succ"); 01020 id_beg = rb_intern("begin"); 01021 id_end = rb_intern("end"); 01022 id_excl = rb_intern("excl"); 01023 01024 rb_cRange = rb_struct_define_without_accessor( 01025 "Range", rb_cObject, range_alloc, 01026 "begin", "end", "excl", NULL); 01027 01028 rb_include_module(rb_cRange, rb_mEnumerable); 01029 rb_marshal_define_compat(rb_cRange, rb_cObject, range_dumper, range_loader); 01030 rb_define_method(rb_cRange, "initialize", range_initialize, -1); 01031 rb_define_method(rb_cRange, "initialize_copy", range_initialize_copy, 1); 01032 rb_define_method(rb_cRange, "==", range_eq, 1); 01033 rb_define_method(rb_cRange, "===", range_eqq, 1); 01034 rb_define_method(rb_cRange, "eql?", range_eql, 1); 01035 rb_define_method(rb_cRange, "hash", range_hash, 0); 01036 rb_define_method(rb_cRange, "each", range_each, 0); 01037 rb_define_method(rb_cRange, "step", range_step, -1); 01038 rb_define_method(rb_cRange, "begin", range_begin, 0); 01039 rb_define_method(rb_cRange, "end", range_end, 0); 01040 rb_define_method(rb_cRange, "first", range_first, -1); 01041 rb_define_method(rb_cRange, "last", range_last, -1); 01042 rb_define_method(rb_cRange, "min", range_min, 0); 01043 rb_define_method(rb_cRange, "max", range_max, 0); 01044 rb_define_method(rb_cRange, "to_s", range_to_s, 0); 01045 rb_define_method(rb_cRange, "inspect", range_inspect, 0); 01046 01047 rb_define_method(rb_cRange, "exclude_end?", range_exclude_end_p, 0); 01048 01049 rb_define_method(rb_cRange, "member?", range_include, 1); 01050 rb_define_method(rb_cRange, "include?", range_include, 1); 01051 rb_define_method(rb_cRange, "cover?", range_cover, 1); 01052 } 01053