range.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   range.c -
00004 
00005   $Author: nagachika $
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 #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 #define RANGE_SET_BEG(r, v) (RSTRUCT_SET(r, 0, v))
00029 #define RANGE_SET_END(r, v) (RSTRUCT_SET(r, 1, v))
00030 #define RANGE_SET_EXCL(r, v) (RSTRUCT_SET(r, 2, v))
00031 #define RBOOL(v) ((v) ? Qtrue : Qfalse)
00032 
00033 #define EXCL(r) RTEST(RANGE_EXCL(r))
00034 
00035 static VALUE
00036 range_failed(void)
00037 {
00038     rb_raise(rb_eArgError, "bad value for range");
00039     return Qnil;                /* dummy */
00040 }
00041 
00042 static VALUE
00043 range_check(VALUE *args)
00044 {
00045     return rb_funcall(args[0], id_cmp, 1, args[1]);
00046 }
00047 
00048 static void
00049 range_init(VALUE range, VALUE beg, VALUE end, VALUE exclude_end)
00050 {
00051     VALUE args[2];
00052 
00053     args[0] = beg;
00054     args[1] = end;
00055 
00056     if (!FIXNUM_P(beg) || !FIXNUM_P(end)) {
00057         VALUE v;
00058 
00059         v = rb_rescue(range_check, (VALUE)args, range_failed, 0);
00060         if (NIL_P(v))
00061             range_failed();
00062     }
00063 
00064     RANGE_SET_EXCL(range, exclude_end);
00065     RANGE_SET_BEG(range, beg);
00066     RANGE_SET_END(range, end);
00067 }
00068 
00069 VALUE
00070 rb_range_new(VALUE beg, VALUE end, int exclude_end)
00071 {
00072     VALUE range = rb_obj_alloc(rb_cRange);
00073 
00074     range_init(range, beg, end, RBOOL(exclude_end));
00075     return range;
00076 }
00077 
00078 static void
00079 range_modify(VALUE range)
00080 {
00081     /* Ranges are immutable, so that they should be initialized only once. */
00082     if (RANGE_EXCL(range) != Qnil) {
00083         rb_name_error(idInitialize, "`initialize' called twice");
00084     }
00085 }
00086 
00087 /*
00088  *  call-seq:
00089  *     Range.new(begin, end, exclude_end=false)    -> rng
00090  *
00091  *  Constructs a range using the given +begin+ and +end+. If the +exclude_end+
00092  *  parameter is omitted or is <code>false</code>, the +rng+ will include
00093  *  the end object; otherwise, it will be excluded.
00094  */
00095 
00096 static VALUE
00097 range_initialize(int argc, VALUE *argv, VALUE range)
00098 {
00099     VALUE beg, end, flags;
00100 
00101     rb_scan_args(argc, argv, "21", &beg, &end, &flags);
00102     range_modify(range);
00103     range_init(range, beg, end, RBOOL(RTEST(flags)));
00104     return Qnil;
00105 }
00106 
00107 /* :nodoc: */
00108 static VALUE
00109 range_initialize_copy(VALUE range, VALUE orig)
00110 {
00111     range_modify(range);
00112     rb_struct_init_copy(range, orig);
00113     return range;
00114 }
00115 
00116 /*
00117  *  call-seq:
00118  *     rng.exclude_end?    -> true or false
00119  *
00120  *  Returns <code>true</code> if the range excludes its end value.
00121  *
00122  *     (1..5).exclude_end?     #=> false
00123  *     (1...5).exclude_end?    #=> true
00124  */
00125 
00126 static VALUE
00127 range_exclude_end_p(VALUE range)
00128 {
00129     return EXCL(range) ? Qtrue : Qfalse;
00130 }
00131 
00132 static VALUE
00133 recursive_equal(VALUE range, VALUE obj, int recur)
00134 {
00135     if (recur) return Qtrue; /* Subtle! */
00136     if (!rb_equal(RANGE_BEG(range), RANGE_BEG(obj)))
00137         return Qfalse;
00138     if (!rb_equal(RANGE_END(range), RANGE_END(obj)))
00139         return Qfalse;
00140 
00141     if (EXCL(range) != EXCL(obj))
00142         return Qfalse;
00143     return Qtrue;
00144 }
00145 
00146 
00147 /*
00148  *  call-seq:
00149  *     rng == obj    -> true or false
00150  *
00151  *  Returns <code>true</code> only if +obj+ is a Range, has equivalent
00152  *  begin and end items (by comparing them with <code>==</code>), and has
00153  *  the same #exclude_end? setting as the range.
00154  *
00155  *    (0..2) == (0..2)            #=> true
00156  *    (0..2) == Range.new(0,2)    #=> true
00157  *    (0..2) == (0...2)           #=> false
00158  *
00159  */
00160 
00161 static VALUE
00162 range_eq(VALUE range, VALUE obj)
00163 {
00164     if (range == obj)
00165         return Qtrue;
00166     if (!rb_obj_is_kind_of(obj, rb_cRange))
00167         return Qfalse;
00168 
00169     return rb_exec_recursive_paired(recursive_equal, range, obj, obj);
00170 }
00171 
00172 static int
00173 r_lt(VALUE a, VALUE b)
00174 {
00175     VALUE r = rb_funcall(a, id_cmp, 1, b);
00176 
00177     if (NIL_P(r))
00178         return (int)Qfalse;
00179     if (rb_cmpint(r, a, b) < 0)
00180         return (int)Qtrue;
00181     return (int)Qfalse;
00182 }
00183 
00184 static int
00185 r_le(VALUE a, VALUE b)
00186 {
00187     int c;
00188     VALUE r = rb_funcall(a, id_cmp, 1, b);
00189 
00190     if (NIL_P(r))
00191         return (int)Qfalse;
00192     c = rb_cmpint(r, a, b);
00193     if (c == 0)
00194         return (int)INT2FIX(0);
00195     if (c < 0)
00196         return (int)Qtrue;
00197     return (int)Qfalse;
00198 }
00199 
00200 
00201 static VALUE
00202 recursive_eql(VALUE range, VALUE obj, int recur)
00203 {
00204     if (recur) return Qtrue; /* Subtle! */
00205     if (!rb_eql(RANGE_BEG(range), RANGE_BEG(obj)))
00206         return Qfalse;
00207     if (!rb_eql(RANGE_END(range), RANGE_END(obj)))
00208         return Qfalse;
00209 
00210     if (EXCL(range) != EXCL(obj))
00211         return Qfalse;
00212     return Qtrue;
00213 }
00214 
00215 /*
00216  *  call-seq:
00217  *     rng.eql?(obj)    -> true or false
00218  *
00219  *  Returns <code>true</code> only if +obj+ is a Range, has equivalent
00220  *  begin and end items (by comparing them with <code>eql?</code>),
00221  *  and has the same #exclude_end? setting as the range.
00222  *
00223  *    (0..2).eql?(0..2)            #=> true
00224  *    (0..2).eql?(Range.new(0,2))  #=> true
00225  *    (0..2).eql?(0...2)           #=> false
00226  *
00227  */
00228 
00229 static VALUE
00230 range_eql(VALUE range, VALUE obj)
00231 {
00232     if (range == obj)
00233         return Qtrue;
00234     if (!rb_obj_is_kind_of(obj, rb_cRange))
00235         return Qfalse;
00236     return rb_exec_recursive_paired(recursive_eql, range, obj, obj);
00237 }
00238 
00239 /*
00240  * call-seq:
00241  *   rng.hash    -> fixnum
00242  *
00243  * Compute a hash-code for this range. Two ranges with equal
00244  * begin and end points (using <code>eql?</code>), and the same
00245  * #exclude_end? value will generate the same hash-code.
00246  */
00247 
00248 static VALUE
00249 range_hash(VALUE range)
00250 {
00251     st_index_t hash = EXCL(range);
00252     VALUE v;
00253 
00254     hash = rb_hash_start(hash);
00255     v = rb_hash(RANGE_BEG(range));
00256     hash = rb_hash_uint(hash, NUM2LONG(v));
00257     v = rb_hash(RANGE_END(range));
00258     hash = rb_hash_uint(hash, NUM2LONG(v));
00259     hash = rb_hash_uint(hash, EXCL(range) << 24);
00260     hash = rb_hash_end(hash);
00261 
00262     return LONG2FIX(hash);
00263 }
00264 
00265 static void
00266 range_each_func(VALUE range, rb_block_call_func *func, VALUE arg)
00267 {
00268     int c;
00269     VALUE b = RANGE_BEG(range);
00270     VALUE e = RANGE_END(range);
00271     VALUE v = b;
00272 
00273     if (EXCL(range)) {
00274         while (r_lt(v, e)) {
00275             (*func) (v, arg, 0, 0, 0);
00276             v = rb_funcall(v, id_succ, 0, 0);
00277         }
00278     }
00279     else {
00280         while ((c = r_le(v, e)) != Qfalse) {
00281             (*func) (v, arg, 0, 0, 0);
00282             if (c == (int)INT2FIX(0))
00283                 break;
00284             v = rb_funcall(v, id_succ, 0, 0);
00285         }
00286     }
00287 }
00288 
00289 static VALUE
00290 sym_step_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg))
00291 {
00292     VALUE *iter = (VALUE *)arg;
00293 
00294     if (FIXNUM_P(iter[0])) {
00295         iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG;
00296     }
00297     else {
00298         iter[0] = rb_funcall(iter[0], '-', 1, INT2FIX(1));
00299     }
00300     if (iter[0] == INT2FIX(0)) {
00301         rb_yield(rb_str_intern(i));
00302         iter[0] = iter[1];
00303     }
00304     return Qnil;
00305 }
00306 
00307 static VALUE
00308 step_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg))
00309 {
00310     VALUE *iter = (VALUE *)arg;
00311 
00312     if (FIXNUM_P(iter[0])) {
00313         iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG;
00314     }
00315     else {
00316         iter[0] = rb_funcall(iter[0], '-', 1, INT2FIX(1));
00317     }
00318     if (iter[0] == INT2FIX(0)) {
00319         rb_yield(i);
00320         iter[0] = iter[1];
00321     }
00322     return Qnil;
00323 }
00324 
00325 static int
00326 discrete_object_p(VALUE obj)
00327 {
00328     if (rb_obj_is_kind_of(obj, rb_cTime)) return FALSE; /* until Time#succ removed */
00329     return rb_respond_to(obj, id_succ);
00330 }
00331 
00332 static VALUE
00333 range_step_size(VALUE range, VALUE args, VALUE eobj)
00334 {
00335     VALUE b = RANGE_BEG(range), e = RANGE_END(range);
00336     VALUE step = INT2FIX(1);
00337     if (args) {
00338         step = RARRAY_AREF(args, 0);
00339         if (!rb_obj_is_kind_of(step, rb_cNumeric)) {
00340             step = rb_to_int(step);
00341         }
00342     }
00343     if (rb_funcall(step, '<', 1, INT2FIX(0))) {
00344         rb_raise(rb_eArgError, "step can't be negative");
00345     }
00346     else if (!rb_funcall(step, '>', 1, INT2FIX(0))) {
00347         rb_raise(rb_eArgError, "step can't be 0");
00348     }
00349 
00350     if (rb_obj_is_kind_of(b, rb_cNumeric) && rb_obj_is_kind_of(e, rb_cNumeric)) {
00351         return ruby_num_interval_step_size(b, e, step, EXCL(range));
00352     }
00353     return Qnil;
00354 }
00355 
00356 /*
00357  *  call-seq:
00358  *     rng.step(n=1) {| obj | block }    -> rng
00359  *     rng.step(n=1)                     -> an_enumerator
00360  *
00361  *  Iterates over the range, passing each <code>n</code>th element to the block.
00362  *  If begin and end are numeric, +n+ is added for each iteration.
00363  *  Otherwise <code>step</code> invokes <code>succ</code> to iterate through
00364  *  range elements.
00365  *
00366  *  If no block is given, an enumerator is returned instead.
00367  *
00368  *    range = Xs.new(1)..Xs.new(10)
00369  *    range.step(2) {|x| puts x}
00370  *    puts
00371  *    range.step(3) {|x| puts x}
00372  *
00373  *  <em>produces:</em>
00374  *
00375  *     1 x
00376  *     3 xxx
00377  *     5 xxxxx
00378  *     7 xxxxxxx
00379  *     9 xxxxxxxxx
00380  *
00381  *     1 x
00382  *     4 xxxx
00383  *     7 xxxxxxx
00384  *    10 xxxxxxxxxx
00385  *
00386  *  See Range for the definition of class Xs.
00387  */
00388 
00389 
00390 static VALUE
00391 range_step(int argc, VALUE *argv, VALUE range)
00392 {
00393     VALUE b, e, step, tmp;
00394 
00395     RETURN_SIZED_ENUMERATOR(range, argc, argv, range_step_size);
00396 
00397     b = RANGE_BEG(range);
00398     e = RANGE_END(range);
00399     if (argc == 0) {
00400         step = INT2FIX(1);
00401     }
00402     else {
00403         rb_scan_args(argc, argv, "01", &step);
00404         if (!rb_obj_is_kind_of(step, rb_cNumeric)) {
00405             step = rb_to_int(step);
00406         }
00407         if (rb_funcall(step, '<', 1, INT2FIX(0))) {
00408             rb_raise(rb_eArgError, "step can't be negative");
00409         }
00410         else if (!rb_funcall(step, '>', 1, INT2FIX(0))) {
00411             rb_raise(rb_eArgError, "step can't be 0");
00412         }
00413     }
00414 
00415     if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */
00416         long end = FIX2LONG(e);
00417         long i, unit = FIX2LONG(step);
00418 
00419         if (!EXCL(range))
00420             end += 1;
00421         i = FIX2LONG(b);
00422         while (i < end) {
00423             rb_yield(LONG2NUM(i));
00424             if (i + unit < i) break;
00425             i += unit;
00426         }
00427 
00428     }
00429     else if (SYMBOL_P(b) && SYMBOL_P(e)) { /* symbols are special */
00430         VALUE args[2], iter[2];
00431 
00432         args[0] = rb_sym_to_s(e);
00433         args[1] = EXCL(range) ? Qtrue : Qfalse;
00434         iter[0] = INT2FIX(1);
00435         iter[1] = step;
00436         rb_block_call(rb_sym_to_s(b), rb_intern("upto"), 2, args, sym_step_i, (VALUE)iter);
00437     }
00438     else if (ruby_float_step(b, e, step, EXCL(range))) {
00439         /* done */
00440     }
00441     else if (rb_obj_is_kind_of(b, rb_cNumeric) ||
00442              !NIL_P(rb_check_to_integer(b, "to_int")) ||
00443              !NIL_P(rb_check_to_integer(e, "to_int"))) {
00444         ID op = EXCL(range) ? '<' : idLE;
00445         VALUE v = b;
00446         int i = 0;
00447 
00448         while (RTEST(rb_funcall(v, op, 1, e))) {
00449             rb_yield(v);
00450             i++;
00451             v = rb_funcall(b, '+', 1, rb_funcall(INT2NUM(i), '*', 1, step));
00452         }
00453     }
00454     else {
00455         tmp = rb_check_string_type(b);
00456 
00457         if (!NIL_P(tmp)) {
00458             VALUE args[2], iter[2];
00459 
00460             b = tmp;
00461             args[0] = e;
00462             args[1] = EXCL(range) ? Qtrue : Qfalse;
00463             iter[0] = INT2FIX(1);
00464             iter[1] = step;
00465             rb_block_call(b, rb_intern("upto"), 2, args, step_i, (VALUE)iter);
00466         }
00467         else {
00468             VALUE args[2];
00469 
00470             if (!discrete_object_p(b)) {
00471                 rb_raise(rb_eTypeError, "can't iterate from %s",
00472                          rb_obj_classname(b));
00473             }
00474             args[0] = INT2FIX(1);
00475             args[1] = step;
00476             range_each_func(range, step_i, (VALUE)args);
00477         }
00478     }
00479     return range;
00480 }
00481 
00482 #if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
00483 union int64_double {
00484     int64_t i;
00485     double d;
00486 };
00487 
00488 static VALUE
00489 int64_as_double_to_num(int64_t i)
00490 {
00491     union int64_double convert;
00492     if (i < 0) {
00493         convert.i = -i;
00494         return DBL2NUM(-convert.d);
00495     }
00496     else {
00497         convert.i = i;
00498         return DBL2NUM(convert.d);
00499     }
00500 }
00501 
00502 static int64_t
00503 double_as_int64(double d)
00504 {
00505     union int64_double convert;
00506     convert.d = fabs(d);
00507     return d < 0 ? -convert.i : convert.i;
00508 }
00509 #endif
00510 
00511 static int
00512 is_integer_p(VALUE v)
00513 {
00514     VALUE is_int = rb_check_funcall(v, id_integer_p, 0, 0);
00515     return RTEST(is_int) && is_int != Qundef;
00516 }
00517 
00518 /*
00519  *  call-seq:
00520  *     rng.bsearch {|obj| block }  -> value
00521  *
00522  *  By using binary search, finds a value in range which meets the given
00523  *  condition in O(log n) where n is the size of the range.
00524  *
00525  *  You can use this method in two use cases: a find-minimum mode and
00526  *  a find-any mode.  In either case, the elements of the range must be
00527  *  monotone (or sorted) with respect to the block.
00528  *
00529  *  In find-minimum mode (this is a good choice for typical use case),
00530  *  the block must return true or false, and there must be a value x
00531  *  so that:
00532  *
00533  *  - the block returns false for any value which is less than x, and
00534  *  - the block returns true for any value which is greater than or
00535  *    equal to i.
00536  *
00537  *  If x is within the range, this method returns the value x.
00538  *  Otherwise, it returns nil.
00539  *
00540  *     ary = [0, 4, 7, 10, 12]
00541  *     (0...ary.size).bsearch {|i| ary[i] >= 4 } #=> 1
00542  *     (0...ary.size).bsearch {|i| ary[i] >= 6 } #=> 2
00543  *     (0...ary.size).bsearch {|i| ary[i] >= 8 } #=> 3
00544  *     (0...ary.size).bsearch {|i| ary[i] >= 100 } #=> nil
00545  *
00546  *     (0.0...Float::INFINITY).bsearch {|x| Math.log(x) >= 0 } #=> 1.0
00547  *
00548  *  In find-any mode (this behaves like libc's bsearch(3)), the block
00549  *  must return a number, and there must be two values x and y (x <= y)
00550  *  so that:
00551  *
00552  *  - the block returns a positive number for v if v < x,
00553  *  - the block returns zero for v if x <= v < y, and
00554  *  - the block returns a negative number for v if y <= v.
00555  *
00556  *  This method returns any value which is within the intersection of
00557  *  the given range and x...y (if any).  If there is no value that
00558  *  satisfies the condition, it returns nil.
00559  *
00560  *     ary = [0, 100, 100, 100, 200]
00561  *     (0..4).bsearch {|i| 100 - ary[i] } #=> 1, 2 or 3
00562  *     (0..4).bsearch {|i| 300 - ary[i] } #=> nil
00563  *     (0..4).bsearch {|i|  50 - ary[i] } #=> nil
00564  *
00565  *  You must not mix the two modes at a time; the block must always
00566  *  return either true/false, or always return a number.  It is
00567  *  undefined which value is actually picked up at each iteration.
00568  */
00569 
00570 static VALUE
00571 range_bsearch(VALUE range)
00572 {
00573     VALUE beg, end;
00574     int smaller, satisfied = 0;
00575 
00576     /* Implementation notes:
00577      * Floats are handled by mapping them to 64 bits integers.
00578      * Apart from sign issues, floats and their 64 bits integer have the
00579      * same order, assuming they are represented as exponent followed
00580      * by the mantissa. This is true with or without implicit bit.
00581      *
00582      * Finding the average of two ints needs to be careful about
00583      * potential overflow (since float to long can use 64 bits)
00584      * as well as the fact that -1/2 can be 0 or -1 in C89.
00585      *
00586      * Note that -0.0 is mapped to the same int as 0.0 as we don't want
00587      * (-1...0.0).bsearch to yield -0.0.
00588      */
00589 
00590 #define BSEARCH_CHECK(val) \
00591     do { \
00592         VALUE v = rb_yield(val); \
00593         if (FIXNUM_P(v)) { \
00594             if (FIX2INT(v) == 0) return val; \
00595             smaller = FIX2INT(v) < 0; \
00596         } \
00597         else if (v == Qtrue) { \
00598             satisfied = 1; \
00599             smaller = 1; \
00600         } \
00601         else if (v == Qfalse || v == Qnil) { \
00602             smaller = 0; \
00603         } \
00604         else if (rb_obj_is_kind_of(v, rb_cNumeric)) { \
00605             int cmp = rb_cmpint(rb_funcall(v, id_cmp, 1, INT2FIX(0)), v, INT2FIX(0)); \
00606             if (!cmp) return val; \
00607             smaller = cmp < 0; \
00608         } \
00609         else { \
00610             rb_raise(rb_eTypeError, "wrong argument type %s" \
00611                 " (must be numeric, true, false or nil)", \
00612                 rb_obj_classname(v)); \
00613         } \
00614     } while (0)
00615 
00616 #define BSEARCH(conv) \
00617     do { \
00618         RETURN_ENUMERATOR(range, 0, 0); \
00619         if (EXCL(range)) high--; \
00620         org_high = high; \
00621         while (low < high) { \
00622             mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \
00623                 : (low < -high) ? -((-1 - low - high)/2 + 1) : (low + high) / 2; \
00624             BSEARCH_CHECK(conv(mid)); \
00625             if (smaller) { \
00626                 high = mid; \
00627             } \
00628             else { \
00629                 low = mid + 1; \
00630             } \
00631         } \
00632         if (low == org_high) { \
00633             BSEARCH_CHECK(conv(low)); \
00634             if (!smaller) return Qnil; \
00635         } \
00636         if (!satisfied) return Qnil; \
00637         return conv(low); \
00638     } while (0)
00639 
00640 
00641     beg = RANGE_BEG(range);
00642     end = RANGE_END(range);
00643 
00644     if (FIXNUM_P(beg) && FIXNUM_P(end)) {
00645         long low = FIX2LONG(beg);
00646         long high = FIX2LONG(end);
00647         long mid, org_high;
00648         BSEARCH(INT2FIX);
00649     }
00650 #if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
00651     else if (RB_TYPE_P(beg, T_FLOAT) || RB_TYPE_P(end, T_FLOAT)) {
00652         int64_t low  = double_as_int64(RFLOAT_VALUE(rb_Float(beg)));
00653         int64_t high = double_as_int64(RFLOAT_VALUE(rb_Float(end)));
00654         int64_t mid, org_high;
00655         BSEARCH(int64_as_double_to_num);
00656     }
00657 #endif
00658     else if (is_integer_p(beg) && is_integer_p(end)) {
00659         VALUE low = rb_to_int(beg);
00660         VALUE high = rb_to_int(end);
00661         VALUE mid, org_high;
00662         RETURN_ENUMERATOR(range, 0, 0);
00663         if (EXCL(range)) high = rb_funcall(high, '-', 1, INT2FIX(1));
00664         org_high = high;
00665 
00666         while (rb_cmpint(rb_funcall(low, id_cmp, 1, high), low, high) < 0) {
00667             mid = rb_funcall(rb_funcall(high, '+', 1, low), id_div, 1, INT2FIX(2));
00668             BSEARCH_CHECK(mid);
00669             if (smaller) {
00670                 high = mid;
00671             }
00672             else {
00673                 low = rb_funcall(mid, '+', 1, INT2FIX(1));
00674             }
00675         }
00676         if (rb_equal(low, org_high)) {
00677             BSEARCH_CHECK(low);
00678             if (!smaller) return Qnil;
00679         }
00680         if (!satisfied) return Qnil;
00681         return low;
00682     }
00683     else {
00684         rb_raise(rb_eTypeError, "can't do binary search for %s", rb_obj_classname(beg));
00685     }
00686     return range;
00687 }
00688 
00689 static VALUE
00690 each_i(RB_BLOCK_CALL_FUNC_ARGLIST(v, arg))
00691 {
00692     rb_yield(v);
00693     return Qnil;
00694 }
00695 
00696 static VALUE
00697 sym_each_i(RB_BLOCK_CALL_FUNC_ARGLIST(v, arg))
00698 {
00699     rb_yield(rb_str_intern(v));
00700     return Qnil;
00701 }
00702 
00703 /*
00704  *  call-seq:
00705  *     rng.size                   -> num
00706  *
00707  *  Returns the number of elements in the range. Both the begin and the end of
00708  *  the Range must be Numeric, otherwise nil is returned.
00709  *
00710  *    (10..20).size    #=> 11
00711  *    ('a'..'z').size  #=> nil
00712  *    (-Float::INFINITY..Float::INFINITY).size #=> Infinity
00713  */
00714 
00715 static VALUE
00716 range_size(VALUE range)
00717 {
00718     VALUE b = RANGE_BEG(range), e = RANGE_END(range);
00719     if (rb_obj_is_kind_of(b, rb_cNumeric) && rb_obj_is_kind_of(e, rb_cNumeric)) {
00720         return ruby_num_interval_step_size(b, e, INT2FIX(1), EXCL(range));
00721     }
00722     return Qnil;
00723 }
00724 
00725 static VALUE
00726 range_enum_size(VALUE range, VALUE args, VALUE eobj)
00727 {
00728     return range_size(range);
00729 }
00730 
00731 /*
00732  *  call-seq:
00733  *     rng.each {| i | block } -> rng
00734  *     rng.each                -> an_enumerator
00735  *
00736  *  Iterates over the elements of range, passing each in turn to the
00737  *  block.
00738  *
00739  *  The +each+ method can only be used if the begin object of the range
00740  *  supports the +succ+ method.  A TypeError is raised if the object
00741  *  does not have +succ+ method defined (like Float).
00742  *
00743  *  If no block is given, an enumerator is returned instead.
00744  *
00745  *     (10..15).each {|n| print n, ' ' }
00746  *     # prints: 10 11 12 13 14 15
00747  *
00748  *     (2.5..5).each {|n| print n, ' ' }
00749  *     # raises: TypeError: can't iterate from Float
00750  */
00751 
00752 static VALUE
00753 range_each(VALUE range)
00754 {
00755     VALUE beg, end;
00756 
00757     RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_size);
00758 
00759     beg = RANGE_BEG(range);
00760     end = RANGE_END(range);
00761 
00762     if (FIXNUM_P(beg) && FIXNUM_P(end)) { /* fixnums are special */
00763         long lim = FIX2LONG(end);
00764         long i;
00765 
00766         if (!EXCL(range))
00767             lim += 1;
00768         for (i = FIX2LONG(beg); i < lim; i++) {
00769             rb_yield(LONG2FIX(i));
00770         }
00771     }
00772     else if (SYMBOL_P(beg) && SYMBOL_P(end)) { /* symbols are special */
00773         VALUE args[2];
00774 
00775         args[0] = rb_sym_to_s(end);
00776         args[1] = EXCL(range) ? Qtrue : Qfalse;
00777         rb_block_call(rb_sym_to_s(beg), rb_intern("upto"), 2, args, sym_each_i, 0);
00778     }
00779     else {
00780         VALUE tmp = rb_check_string_type(beg);
00781 
00782         if (!NIL_P(tmp)) {
00783             VALUE args[2];
00784 
00785             args[0] = end;
00786             args[1] = EXCL(range) ? Qtrue : Qfalse;
00787             rb_block_call(tmp, rb_intern("upto"), 2, args, each_i, 0);
00788         }
00789         else {
00790             if (!discrete_object_p(beg)) {
00791                 rb_raise(rb_eTypeError, "can't iterate from %s",
00792                          rb_obj_classname(beg));
00793             }
00794             range_each_func(range, each_i, 0);
00795         }
00796     }
00797     return range;
00798 }
00799 
00800 /*
00801  *  call-seq:
00802  *     rng.begin    -> obj
00803  *
00804  *  Returns the object that defines the beginning of the range.
00805  *
00806  *      (1..10).begin   #=> 1
00807  */
00808 
00809 static VALUE
00810 range_begin(VALUE range)
00811 {
00812     return RANGE_BEG(range);
00813 }
00814 
00815 
00816 /*
00817  *  call-seq:
00818  *     rng.end    -> obj
00819  *
00820  *  Returns the object that defines the end of the range.
00821  *
00822  *     (1..10).end    #=> 10
00823  *     (1...10).end   #=> 10
00824  */
00825 
00826 
00827 static VALUE
00828 range_end(VALUE range)
00829 {
00830     return RANGE_END(range);
00831 }
00832 
00833 
00834 static VALUE
00835 first_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, cbarg))
00836 {
00837     VALUE *ary = (VALUE *)cbarg;
00838     long n = NUM2LONG(ary[0]);
00839 
00840     if (n <= 0) {
00841         rb_iter_break();
00842     }
00843     rb_ary_push(ary[1], i);
00844     n--;
00845     ary[0] = INT2NUM(n);
00846     return Qnil;
00847 }
00848 
00849 /*
00850  *  call-seq:
00851  *     rng.first    -> obj
00852  *     rng.first(n) -> an_array
00853  *
00854  *  Returns the first object in the range, or an array of the first +n+
00855  *  elements.
00856  *
00857  *    (10..20).first     #=> 10
00858  *    (10..20).first(3)  #=> [10, 11, 12]
00859  */
00860 
00861 static VALUE
00862 range_first(int argc, VALUE *argv, VALUE range)
00863 {
00864     VALUE n, ary[2];
00865 
00866     if (argc == 0) return RANGE_BEG(range);
00867 
00868     rb_scan_args(argc, argv, "1", &n);
00869     ary[0] = n;
00870     ary[1] = rb_ary_new2(NUM2LONG(n));
00871     rb_block_call(range, idEach, 0, 0, first_i, (VALUE)ary);
00872 
00873     return ary[1];
00874 }
00875 
00876 
00877 /*
00878  *  call-seq:
00879  *     rng.last    -> obj
00880  *     rng.last(n) -> an_array
00881  *
00882  *  Returns the last object in the range,
00883  *  or an array of the last +n+ elements.
00884  *
00885  *  Note that with no arguments +last+ will return the object that defines
00886  *  the end of the range even if #exclude_end? is +true+.
00887  *
00888  *    (10..20).last      #=> 20
00889  *    (10...20).last     #=> 20
00890  *    (10..20).last(3)   #=> [18, 19, 20]
00891  *    (10...20).last(3)  #=> [17, 18, 19]
00892  */
00893 
00894 static VALUE
00895 range_last(int argc, VALUE *argv, VALUE range)
00896 {
00897     if (argc == 0) return RANGE_END(range);
00898     return rb_ary_last(argc, argv, rb_Array(range));
00899 }
00900 
00901 
00902 /*
00903  *  call-seq:
00904  *     rng.min                    -> obj
00905  *     rng.min {| a,b | block }   -> obj
00906  *
00907  *  Returns the minimum value in the range. Returns +nil+ if the begin
00908  *  value of the range is larger than the end value.
00909  *
00910  *  Can be given an optional block to override the default comparison
00911  *  method <code>a <=> b</code>.
00912  *
00913  *    (10..20).min    #=> 10
00914  */
00915 
00916 
00917 static VALUE
00918 range_min(VALUE range)
00919 {
00920     if (rb_block_given_p()) {
00921         return rb_call_super(0, 0);
00922     }
00923     else {
00924         VALUE b = RANGE_BEG(range);
00925         VALUE e = RANGE_END(range);
00926         int c = rb_cmpint(rb_funcall(b, id_cmp, 1, e), b, e);
00927 
00928         if (c > 0 || (c == 0 && EXCL(range)))
00929             return Qnil;
00930         return b;
00931     }
00932 }
00933 
00934 /*
00935  *  call-seq:
00936  *     rng.max                    -> obj
00937  *     rng.max {| a,b | block }   -> obj
00938  *
00939  *  Returns the maximum value in the range. Returns +nil+ if the begin
00940  *  value of the range larger than the end value.
00941  *
00942  *  Can be given an optional block to override the default comparison
00943  *  method <code>a <=> b</code>.
00944  *
00945  *    (10..20).max    #=> 20
00946  */
00947 
00948 static VALUE
00949 range_max(VALUE range)
00950 {
00951     VALUE e = RANGE_END(range);
00952     int nm = FIXNUM_P(e) || rb_obj_is_kind_of(e, rb_cNumeric);
00953 
00954     if (rb_block_given_p() || (EXCL(range) && !nm)) {
00955         return rb_call_super(0, 0);
00956     }
00957     else {
00958         VALUE b = RANGE_BEG(range);
00959         int c = rb_cmpint(rb_funcall(b, id_cmp, 1, e), b, e);
00960 
00961         if (c > 0)
00962             return Qnil;
00963         if (EXCL(range)) {
00964             if (!FIXNUM_P(e) && !rb_obj_is_kind_of(e, rb_cInteger)) {
00965                 rb_raise(rb_eTypeError, "cannot exclude non Integer end value");
00966             }
00967             if (c == 0) return Qnil;
00968             if (!FIXNUM_P(b) && !rb_obj_is_kind_of(b,rb_cInteger)) {
00969                 rb_raise(rb_eTypeError, "cannot exclude end value with non Integer begin value");
00970             }
00971             if (FIXNUM_P(e)) {
00972                 return LONG2NUM(FIX2LONG(e) - 1);
00973             }
00974             return rb_funcall(e, '-', 1, INT2FIX(1));
00975         }
00976         return e;
00977     }
00978 }
00979 
00980 int
00981 rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
00982 {
00983     VALUE b, e;
00984     int excl;
00985 
00986     if (rb_obj_is_kind_of(range, rb_cRange)) {
00987         b = RANGE_BEG(range);
00988         e = RANGE_END(range);
00989         excl = EXCL(range);
00990     }
00991     else {
00992         if (!rb_respond_to(range, id_beg)) return (int)Qfalse;
00993         if (!rb_respond_to(range, id_end)) return (int)Qfalse;
00994         b = rb_funcall(range, id_beg, 0);
00995         e = rb_funcall(range, id_end, 0);
00996         excl = RTEST(rb_funcall(range, rb_intern("exclude_end?"), 0));
00997     }
00998     *begp = b;
00999     *endp = e;
01000     *exclp = excl;
01001     return (int)Qtrue;
01002 }
01003 
01004 VALUE
01005 rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
01006 {
01007     long beg, end, origbeg, origend;
01008     VALUE b, e;
01009     int excl;
01010 
01011     if (!rb_range_values(range, &b, &e, &excl))
01012         return Qfalse;
01013     beg = NUM2LONG(b);
01014     end = NUM2LONG(e);
01015     origbeg = beg;
01016     origend = end;
01017     if (beg < 0) {
01018         beg += len;
01019         if (beg < 0)
01020             goto out_of_range;
01021     }
01022     if (end < 0)
01023         end += len;
01024     if (!excl)
01025         end++;                  /* include end point */
01026     if (err == 0 || err == 2) {
01027         if (beg > len)
01028             goto out_of_range;
01029         if (end > len)
01030             end = len;
01031     }
01032     len = end - beg;
01033     if (len < 0)
01034         len = 0;
01035 
01036     *begp = beg;
01037     *lenp = len;
01038     return Qtrue;
01039 
01040   out_of_range:
01041     if (err) {
01042         rb_raise(rb_eRangeError, "%ld..%s%ld out of range",
01043                  origbeg, excl ? "." : "", origend);
01044     }
01045     return Qnil;
01046 }
01047 
01048 /*
01049  * call-seq:
01050  *   rng.to_s   -> string
01051  *
01052  * Convert this range object to a printable form (using #to_s to convert the
01053  * begin and end objects).
01054  */
01055 
01056 static VALUE
01057 range_to_s(VALUE range)
01058 {
01059     VALUE str, str2;
01060 
01061     str = rb_obj_as_string(RANGE_BEG(range));
01062     str2 = rb_obj_as_string(RANGE_END(range));
01063     str = rb_str_dup(str);
01064     rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
01065     rb_str_append(str, str2);
01066     OBJ_INFECT(str, str2);
01067 
01068     return str;
01069 }
01070 
01071 static VALUE
01072 inspect_range(VALUE range, VALUE dummy, int recur)
01073 {
01074     VALUE str, str2;
01075 
01076     if (recur) {
01077         return rb_str_new2(EXCL(range) ? "(... ... ...)" : "(... .. ...)");
01078     }
01079     str = rb_inspect(RANGE_BEG(range));
01080     str2 = rb_inspect(RANGE_END(range));
01081     str = rb_str_dup(str);
01082     rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
01083     rb_str_append(str, str2);
01084     OBJ_INFECT(str, str2);
01085 
01086     return str;
01087 }
01088 
01089 /*
01090  * call-seq:
01091  *   rng.inspect  -> string
01092  *
01093  * Convert this range object to a printable form (using
01094  * <code>inspect</code> to convert the begin and end
01095  * objects).
01096  */
01097 
01098 
01099 static VALUE
01100 range_inspect(VALUE range)
01101 {
01102     return rb_exec_recursive(inspect_range, range, 0);
01103 }
01104 
01105 /*
01106  *  call-seq:
01107  *     rng === obj       ->  true or false
01108  *
01109  *  Returns <code>true</code> if +obj+ is an element of the range,
01110  *  <code>false</code> otherwise.  Conveniently, <code>===</code> is the
01111  *  comparison operator used by <code>case</code> statements.
01112  *
01113  *     case 79
01114  *     when 1..50   then   print "low\n"
01115  *     when 51..75  then   print "medium\n"
01116  *     when 76..100 then   print "high\n"
01117  *     end
01118  *
01119  *  <em>produces:</em>
01120  *
01121  *     high
01122  */
01123 
01124 static VALUE
01125 range_eqq(VALUE range, VALUE val)
01126 {
01127     return rb_funcall(range, rb_intern("include?"), 1, val);
01128 }
01129 
01130 
01131 /*
01132  *  call-seq:
01133  *     rng.member?(obj)  ->  true or false
01134  *     rng.include?(obj) ->  true or false
01135  *
01136  *  Returns <code>true</code> if +obj+ is an element of
01137  *  the range, <code>false</code> otherwise.  If begin and end are
01138  *  numeric, comparison is done according to the magnitude of the values.
01139  *
01140  *     ("a".."z").include?("g")   #=> true
01141  *     ("a".."z").include?("A")   #=> false
01142  *     ("a".."z").include?("cc")  #=> false
01143  */
01144 
01145 static VALUE
01146 range_include(VALUE range, VALUE val)
01147 {
01148     VALUE beg = RANGE_BEG(range);
01149     VALUE end = RANGE_END(range);
01150     int nv = FIXNUM_P(beg) || FIXNUM_P(end) ||
01151              rb_obj_is_kind_of(beg, rb_cNumeric) ||
01152              rb_obj_is_kind_of(end, rb_cNumeric);
01153 
01154     if (nv ||
01155         !NIL_P(rb_check_to_integer(beg, "to_int")) ||
01156         !NIL_P(rb_check_to_integer(end, "to_int"))) {
01157         if (r_le(beg, val)) {
01158             if (EXCL(range)) {
01159                 if (r_lt(val, end))
01160                     return Qtrue;
01161             }
01162             else {
01163                 if (r_le(val, end))
01164                     return Qtrue;
01165             }
01166         }
01167         return Qfalse;
01168     }
01169     else if (RB_TYPE_P(beg, T_STRING) && RB_TYPE_P(end, T_STRING) &&
01170              RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) {
01171         if (NIL_P(val)) return Qfalse;
01172         if (RB_TYPE_P(val, T_STRING)) {
01173             if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1)
01174                 return Qfalse;
01175             else {
01176                 char b = RSTRING_PTR(beg)[0];
01177                 char e = RSTRING_PTR(end)[0];
01178                 char v = RSTRING_PTR(val)[0];
01179 
01180                 if (ISASCII(b) && ISASCII(e) && ISASCII(v)) {
01181                     if (b <= v && v < e) return Qtrue;
01182                     if (!EXCL(range) && v == e) return Qtrue;
01183                     return Qfalse;
01184                 }
01185             }
01186         }
01187     }
01188     /* TODO: ruby_frame->this_func = rb_intern("include?"); */
01189     return rb_call_super(1, &val);
01190 }
01191 
01192 
01193 /*
01194  *  call-seq:
01195  *     rng.cover?(obj)  ->  true or false
01196  *
01197  *  Returns <code>true</code> if +obj+ is between the begin and end of
01198  *  the range.
01199  *
01200  *  This tests <code>begin <= obj <= end</code> when #exclude_end? is +false+
01201  *  and <code>begin <= obj < end</code> when #exclude_end? is +true+.
01202  *
01203  *     ("a".."z").cover?("c")    #=> true
01204  *     ("a".."z").cover?("5")    #=> false
01205  *     ("a".."z").cover?("cc")   #=> true
01206  */
01207 
01208 static VALUE
01209 range_cover(VALUE range, VALUE val)
01210 {
01211     VALUE beg, end;
01212 
01213     beg = RANGE_BEG(range);
01214     end = RANGE_END(range);
01215     if (r_le(beg, val)) {
01216         if (EXCL(range)) {
01217             if (r_lt(val, end))
01218                 return Qtrue;
01219         }
01220         else {
01221             if (r_le(val, end))
01222                 return Qtrue;
01223         }
01224     }
01225     return Qfalse;
01226 }
01227 
01228 static VALUE
01229 range_dumper(VALUE range)
01230 {
01231     VALUE v;
01232     NEWOBJ_OF(m, struct RObject, rb_cObject, T_OBJECT | (RGENGC_WB_PROTECTED_OBJECT ? FL_WB_PROTECTED : 1));
01233 
01234     v = (VALUE)m;
01235 
01236     rb_ivar_set(v, id_excl, RANGE_EXCL(range));
01237     rb_ivar_set(v, id_beg, RANGE_BEG(range));
01238     rb_ivar_set(v, id_end, RANGE_END(range));
01239     return v;
01240 }
01241 
01242 static VALUE
01243 range_loader(VALUE range, VALUE obj)
01244 {
01245     if (!RB_TYPE_P(obj, T_OBJECT) || RBASIC(obj)->klass != rb_cObject) {
01246         rb_raise(rb_eTypeError, "not a dumped range object");
01247     }
01248 
01249     range_modify(range);
01250     RANGE_SET_BEG(range, rb_ivar_get(obj, id_beg));
01251     RANGE_SET_END(range, rb_ivar_get(obj, id_end));
01252     RANGE_SET_EXCL(range, rb_ivar_get(obj, id_excl));
01253     return range;
01254 }
01255 
01256 static VALUE
01257 range_alloc(VALUE klass)
01258 {
01259   /* rb_struct_alloc_noinit itself should not be used because
01260    * rb_marshal_define_compat uses equality of allocation function */
01261     return rb_struct_alloc_noinit(klass);
01262 }
01263 
01264 /*  A <code>Range</code> represents an interval---a set of values with a
01265  *  beginning and an end. Ranges may be constructed using the
01266  *  <em>s</em><code>..</code><em>e</em> and
01267  *  <em>s</em><code>...</code><em>e</em> literals, or with
01268  *  Range::new. Ranges constructed using <code>..</code>
01269  *  run from the beginning to the end inclusively. Those created using
01270  *  <code>...</code> exclude the end value. When used as an iterator,
01271  *  ranges return each value in the sequence.
01272  *
01273  *     (-1..-5).to_a      #=> []
01274  *     (-5..-1).to_a      #=> [-5, -4, -3, -2, -1]
01275  *     ('a'..'e').to_a    #=> ["a", "b", "c", "d", "e"]
01276  *     ('a'...'e').to_a   #=> ["a", "b", "c", "d"]
01277  *
01278  *  == Custom Objects in Ranges
01279  *
01280  *  Ranges can be constructed using any objects that can be compared
01281  *  using the <code><=></code> operator.
01282  *  Methods that treat the range as a sequence (#each and methods inherited
01283  *  from Enumerable) expect the begin object to implement a
01284  *  <code>succ</code> method to return the next object in sequence.
01285  *  The #step and #include? methods require the begin
01286  *  object to implement <code>succ</code> or to be numeric.
01287  *
01288  *  In the <code>Xs</code> class below both <code><=></code> and
01289  *  <code>succ</code> are implemented so <code>Xs</code> can be used
01290  *  to construct ranges. Note that the Comparable module is included
01291  *  so the <code>==</code> method is defined in terms of <code><=></code>.
01292  *
01293  *     class Xs                # represent a string of 'x's
01294  *       include Comparable
01295  *       attr :length
01296  *       def initialize(n)
01297  *         @length = n
01298  *       end
01299  *       def succ
01300  *         Xs.new(@length + 1)
01301  *       end
01302  *       def <=>(other)
01303  *         @length <=> other.length
01304  *       end
01305  *       def to_s
01306  *         sprintf "%2d #{inspect}", @length
01307  *       end
01308  *       def inspect
01309  *         'x' * @length
01310  *       end
01311  *     end
01312  *
01313  *  An example of using <code>Xs</code> to construct a range:
01314  *
01315  *     r = Xs.new(3)..Xs.new(6)   #=> xxx..xxxxxx
01316  *     r.to_a                     #=> [xxx, xxxx, xxxxx, xxxxxx]
01317  *     r.member?(Xs.new(5))       #=> true
01318  *
01319  */
01320 
01321 void
01322 Init_Range(void)
01323 {
01324 #undef rb_intern
01325 #define rb_intern(str) rb_intern_const(str)
01326 
01327     id_cmp = rb_intern("<=>");
01328     id_succ = rb_intern("succ");
01329     id_beg = rb_intern("begin");
01330     id_end = rb_intern("end");
01331     id_excl = rb_intern("excl");
01332     id_integer_p = rb_intern("integer?");
01333     id_div = rb_intern("div");
01334 
01335     rb_cRange = rb_struct_define_without_accessor(
01336         "Range", rb_cObject, range_alloc,
01337         "begin", "end", "excl", NULL);
01338 
01339     rb_include_module(rb_cRange, rb_mEnumerable);
01340     rb_marshal_define_compat(rb_cRange, rb_cObject, range_dumper, range_loader);
01341     rb_define_method(rb_cRange, "initialize", range_initialize, -1);
01342     rb_define_method(rb_cRange, "initialize_copy", range_initialize_copy, 1);
01343     rb_define_method(rb_cRange, "==", range_eq, 1);
01344     rb_define_method(rb_cRange, "===", range_eqq, 1);
01345     rb_define_method(rb_cRange, "eql?", range_eql, 1);
01346     rb_define_method(rb_cRange, "hash", range_hash, 0);
01347     rb_define_method(rb_cRange, "each", range_each, 0);
01348     rb_define_method(rb_cRange, "step", range_step, -1);
01349     rb_define_method(rb_cRange, "bsearch", range_bsearch, 0);
01350     rb_define_method(rb_cRange, "begin", range_begin, 0);
01351     rb_define_method(rb_cRange, "end", range_end, 0);
01352     rb_define_method(rb_cRange, "first", range_first, -1);
01353     rb_define_method(rb_cRange, "last", range_last, -1);
01354     rb_define_method(rb_cRange, "min", range_min, 0);
01355     rb_define_method(rb_cRange, "max", range_max, 0);
01356     rb_define_method(rb_cRange, "size", range_size, 0);
01357     rb_define_method(rb_cRange, "to_s", range_to_s, 0);
01358     rb_define_method(rb_cRange, "inspect", range_inspect, 0);
01359 
01360     rb_define_method(rb_cRange, "exclude_end?", range_exclude_end_p, 0);
01361 
01362     rb_define_method(rb_cRange, "member?", range_include, 1);
01363     rb_define_method(rb_cRange, "include?", range_include, 1);
01364     rb_define_method(rb_cRange, "cover?", range_cover, 1);
01365 }
01366 

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7