summaryrefslogtreecommitdiff
path: root/range.c
diff options
context:
space:
mode:
Diffstat (limited to 'range.c')
-rw-r--r--range.c191
1 files changed, 135 insertions, 56 deletions
diff --git a/range.c b/range.c
index 30c9996..74bbdcd 100644
--- a/range.c
+++ b/range.c
@@ -13,8 +13,10 @@
#include "ruby.h"
VALUE rb_cRange;
-static ID id_upto, id_cmp;
-static ID id_beg, id_end;
+static ID id_cmp, id_beg, id_end;
+
+#define EXCL(r) FL_TEST((r), FL_USER1)
+#define SET_EXCL(r) FL_SET((r), FL_USER1)
static VALUE
range_check(args)
@@ -31,8 +33,9 @@ range_failed()
}
static VALUE
-range_s_new(klass, beg, end)
+range_new(klass, beg, end, exclude_end)
VALUE klass, beg, end;
+ int exclude_end;
{
VALUE obj;
VALUE args[2];
@@ -43,6 +46,9 @@ range_s_new(klass, beg, end)
}
obj = rb_obj_alloc(klass);
+ if (exclude_end) {
+ SET_EXCL(obj);
+ }
rb_ivar_set(obj, id_beg, beg);
rb_ivar_set(obj, id_end, end);
@@ -52,67 +58,97 @@ range_s_new(klass, beg, end)
}
VALUE
-rb_range_new(beg, end)
+rb_range_new(beg, end, exclude_end)
VALUE beg, end;
+ int exclude_end;
+{
+ return range_new(rb_cRange, beg, end, exclude_end);
+}
+
+static VALUE
+range_s_new(argc, argv, klass)
+ int argc;
+ VALUE *argv;
+ VALUE klass;
+{
+ VALUE beg, end, flag, range;
+
+ rb_scan_args(argc, argv, "21", &beg, &end, &flag);
+ if (argc == 2) flag == Qtrue;
+ return range_new(klass, beg, end, RTEST(flag));
+}
+
+static VALUE
+range_exclude_end_p(range)
+ VALUE range;
{
- return range_s_new(rb_cRange, beg, end);
+ return EXCL(range)?Qtrue:Qfalse;;
}
static VALUE
-range_eqq(rng, obj)
- VALUE rng, obj;
+range_eqq(range, obj)
+ VALUE range, obj;
{
VALUE beg, end;
- beg = rb_ivar_get(rng, id_beg);
- end = rb_ivar_get(rng, id_end);
+ beg = rb_ivar_get(range, id_beg);
+ end = rb_ivar_get(range, id_end);
if (FIXNUM_P(beg) && FIXNUM_P(obj) && FIXNUM_P(end)) {
- if (FIX2INT(beg) <= FIX2INT(obj) && FIX2INT(obj) <= FIX2INT(end)) {
- return Qtrue;
+ if (FIX2INT(beg) <= FIX2INT(obj)) {
+ if (EXCL(range)) {
+ if (FIX2INT(obj) <= FIX2INT(end)) return Qtrue;
+ }
+ else {
+ if (FIX2INT(obj) < FIX2INT(end)) return Qtrue;
+ }
}
return Qfalse;
}
- else {
- if (RTEST(rb_funcall(beg, rb_intern("<="), 1, obj)) &&
- RTEST(rb_funcall(end, rb_intern(">="), 1, obj))) {
- return Qtrue;
+ else if (RTEST(rb_funcall(beg, rb_intern("<="), 1, obj))) {
+ if (EXCL(range)) {
+ if (RTEST(rb_funcall(end, rb_intern(">="), 1, obj)))
+ return Qtrue;
+ }
+ else {
+ if (RTEST(rb_funcall(end, rb_intern(">"), 1, obj)))
+ return Qtrue;
+ if (FIX2INT(obj) < FIX2INT(end)) return Qtrue;
}
- return Qfalse;
}
+ return Qfalse;
}
-struct upto_data {
- VALUE beg;
- VALUE end;
-};
-
static VALUE
-range_upto(data)
- struct upto_data *data;
-{
- return rb_funcall(data->beg, id_upto, 1, data->end);
-}
-
-static VALUE
-range_each(obj)
- VALUE obj;
+range_each(range)
+ VALUE range;
{
VALUE b, e;
- b = rb_ivar_get(obj, id_beg);
- e = rb_ivar_get(obj, id_end);
-
- if (FIXNUM_P(b)) { /* fixnum is a special case(for performance) */
- rb_fix_upto(b, e);
- }
- else {
- struct upto_data data;
+ b = rb_ivar_get(range, id_beg);
+ e = rb_ivar_get(range, id_end);
- data.beg = b;
- data.end = e;
+ if (FIXNUM_P(b) && FIXNUM_P(e)) { /* fixnums are special */
+ long end = FIX2LONG(e);
+ long i;
- rb_iterate(range_upto, (VALUE)&data, rb_yield, 0);
+ if (!EXCL(range)) end += 1;
+ for (i=FIX2LONG(b); i<end; i++) {
+ rb_yield(INT2FIX(i));
+ }
+ }
+ else if (TYPE(b) == T_STRING) {
+ rb_str_upto(b, e, EXCL(range));
+ }
+ else { /* generic each */
+ VALUE v = b;
+ ID le = EXCL(range)?'<':rb_intern("<=");
+ ID succ = rb_intern("succ");
+
+ while (rb_funcall(v, le, 1, e)) {
+ rb_yield(v);
+ v = rb_funcall(v, succ, 0, 0);
+ }
}
return Qnil;
@@ -139,17 +175,49 @@ range_last(obj)
}
VALUE
-rb_range_beg_end(range, begp, endp)
+rb_range_beg_len(range, begp, lenp, len, err)
VALUE range;
- int *begp, *endp;
+ int *begp, *lenp;
+ int len, err;
{
- VALUE beg, end;
+ int beg, end, b, e;
if (!rb_obj_is_kind_of(range, rb_cRange)) return Qfalse;
- beg = rb_ivar_get(range, id_beg); *begp = NUM2INT(beg);
- end = rb_ivar_get(range, id_end); *endp = NUM2INT(end);
+ beg = b = NUM2INT(rb_ivar_get(range, id_beg));
+ end = e = NUM2INT(rb_ivar_get(range, id_end));
+
+ if (beg < 0) {
+ beg += len;
+ if (beg < 0) goto out_of_range;
+ }
+ if (err == 2 && beg > len) goto out_of_range;
+ if (end < 0) {
+ end += len;
+ if (end < 0) {
+ if (err == 1 && e == -1 && !EXCL(range)) {
+ len = 0;
+ goto length_set;
+ }
+ goto out_of_range;
+ }
+ }
+ len = end - beg;
+ if (!EXCL(range)) len++; /* include end point */
+ if (len < 0) goto out_of_range;
+
+ length_set:
+ *begp = beg;
+ *lenp = len;
+
return Qtrue;
+
+ out_of_range:
+ if (err) {
+ rb_raise(rb_eIndexError, "%d..%s%d out of range",
+ b, EXCL(range)?".":"", e);
+ }
+ return Qnil;
}
static VALUE
@@ -160,7 +228,7 @@ range_to_s(range)
str = rb_obj_as_string(rb_ivar_get(range, id_beg));
str2 = rb_obj_as_string(rb_ivar_get(range, id_end));
- rb_str_cat(str, "..", 2);
+ rb_str_cat(str, "...", EXCL(range)?3:2);
rb_str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len);
return str;
@@ -174,30 +242,40 @@ range_inspect(range)
str = rb_inspect(rb_ivar_get(range, id_beg));
str2 = rb_inspect(rb_ivar_get(range, id_end));
- rb_str_cat(str, "..", 2);
+ rb_str_cat(str, "...", EXCL(range)?3:2);
rb_str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len);
return str;
}
static VALUE
-range_length(rng)
- VALUE rng;
+range_length(range)
+ VALUE range;
{
VALUE beg, end;
VALUE size;
- beg = rb_ivar_get(rng, id_beg);
- end = rb_ivar_get(rng, id_end);
+ beg = rb_ivar_get(range, id_beg);
+ end = rb_ivar_get(range, id_end);
if (RTEST(rb_funcall(beg, '>', 1, end))) {
return INT2FIX(0);
}
+ if (FIXNUM_P(beg) && FIXNUM_P(end)) {
+ if (EXCL(range)) {
+ return INT2FIX(FIX2INT(end) - FIX2INT(beg));
+ }
+ else {
+ return INT2FIX(FIX2INT(end) - FIX2INT(beg) + 1);
+ }
+ }
if (!rb_obj_is_kind_of(beg, rb_cNumeric)) {
- return rb_enum_length(rng);
+ return rb_enum_length(range);
}
size = rb_funcall(end, '-', 1, beg);
- size = rb_funcall(size, '+', 1, INT2FIX(1));
+ if (!EXCL(range)) {
+ size = rb_funcall(size, '+', 1, INT2FIX(1));
+ }
return size;
}
@@ -207,7 +285,7 @@ Init_Range()
{
rb_cRange = rb_define_class("Range", rb_cObject);
rb_include_module(rb_cRange, rb_mEnumerable);
- rb_define_singleton_method(rb_cRange, "new", range_s_new, 2);
+ rb_define_singleton_method(rb_cRange, "new", range_s_new, -1);
rb_define_method(rb_cRange, "===", range_eqq, 1);
rb_define_method(rb_cRange, "each", range_each, 0);
rb_define_method(rb_cRange, "first", range_first, 0);
@@ -217,10 +295,11 @@ Init_Range()
rb_define_method(rb_cRange, "to_s", range_to_s, 0);
rb_define_method(rb_cRange, "inspect", range_inspect, 0);
+ rb_define_method(rb_cRange, "exclude_end?", range_exclude_end_p, 0);
+
rb_define_method(rb_cRange, "length", range_length, 0);
rb_define_method(rb_cRange, "size", range_length, 0);
- id_upto = rb_intern("upto");
id_cmp = rb_intern("<=>");
id_beg = rb_intern("begin");
id_end = rb_intern("end");