From 65a5162550f58047974793cdc8067a970b2435c0 Mon Sep 17 00:00:00 2001 From: matz Date: Fri, 13 Aug 1999 05:45:20 +0000 Subject: 1.4.0 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@520 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- range.c | 201 ++++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 139 insertions(+), 62 deletions(-) (limited to 'range.c') diff --git a/range.c b/range.c index 9fc363e2a8..d37dfaa21f 100644 --- a/range.c +++ b/range.c @@ -6,15 +6,17 @@ $Date$ created at: Thu Aug 19 17:46:47 JST 1993 - Copyright (C) 1993-1998 Yukihiro Matsumoto + Copyright (C) 1993-1999 Yukihiro Matsumoto ************************************************/ #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,92 +33,119 @@ 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]; + args[0] = beg; args[1] = end; if (!FIXNUM_P(beg) || !FIXNUM_P(end)) { - VALUE args[2]; - - args[0] = beg; args[1] = end; rb_rescue(range_check, (VALUE)args, range_failed, 0); } 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); - rb_obj_call_init(obj); return obj; } 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; + + rb_scan_args(argc, argv, "21", &beg, &end, &flag); + 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 (NUM2LONG(beg) <= NUM2LONG(obj)) { + if (EXCL(range)) { + if (NUM2LONG(obj) < NUM2LONG(end)) return Qtrue; + } + else { + if (NUM2LONG(obj) <= NUM2LONG(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; } - 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 len) goto out_of_range; + if (end > len || (!EXCL(range) && end == len)) + end = len; + } + if (end < 0) { + end += len; + if (end < 0) { + if (beg == 0 && end == -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 @@ -161,7 +227,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; @@ -175,30 +241,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 INT2NUM(NUM2LONG(end) - NUM2LONG(beg)); + } + else { + return INT2NUM(NUM2LONG(end) - NUM2LONG(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; } @@ -208,7 +284,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); @@ -218,10 +294,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"); -- cgit v1.2.3