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