diff --git a/include/mruby/range.h b/include/mruby/range.h index 4df5ccc70..b5626993a 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -38,7 +38,7 @@ struct RRange { mrb_range_edges *edges; mrb_bool excl; }; -# define mrb_gc_free_range(mrb, p) mrb_free(mrb, ((struct RRange*)p)->edges) +# define mrb_gc_free_range(mrb, p) mrb_free(mrb, (p)->edges) # define RANGE_BEG(p) ((p)->edges->beg) # define RANGE_END(p) ((p)->edges->end) #endif diff --git a/src/range.c b/src/range.c index d2f897bd5..2f2521f5e 100644 --- a/src/range.c +++ b/src/range.c @@ -14,20 +14,8 @@ #define RANGE_INITIALIZED(p) ((p)->flags |= RANGE_INITIALIZED_MASK) #define RANGE_INITIALIZED_P(p) ((p)->flags & RANGE_INITIALIZED_MASK) -MRB_API struct RRange* -mrb_range_ptr(mrb_state *mrb, mrb_value range) -{ - struct RRange *r = mrb_range_raw_ptr(range); - - /* check for if #initialize_copy was removed [#3320] */ - if (!RANGE_INITIALIZED_P(r)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range"); - } - return r; -} - static void -range_check(mrb_state *mrb, mrb_value a, mrb_value b) +r_check(mrb_state *mrb, mrb_value a, mrb_value b) { mrb_value ans; enum mrb_vtype ta; @@ -51,159 +39,6 @@ range_check(mrb_state *mrb, mrb_value a, mrb_value b) } } -static void -range_ptr_alloc_edges(mrb_state *mrb, struct RRange *r) -{ -#ifndef MRB_RANGE_EMBED - r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); -#endif -} - -static struct RRange * -range_ptr_init(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, mrb_bool excl) -{ - range_check(mrb, beg, end); - - if (r) { - if (RANGE_INITIALIZED_P(r)) { - /* Ranges are immutable, so that they should be initialized only once. */ - mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); - } - else { - range_ptr_alloc_edges(mrb, r); - } - } - else { - r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class); - range_ptr_alloc_edges(mrb, r); - } - - RANGE_BEG(r) = beg; - RANGE_END(r) = end; - RANGE_EXCL(r) = excl; - RANGE_INITIALIZED(r); - - return r; -} - -static void -range_ptr_replace(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, mrb_bool excl) -{ - range_ptr_init(mrb, r, beg, end, excl); - mrb_write_barrier(mrb, (struct RBasic*)r); -} - -MRB_API mrb_value -mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) -{ - struct RRange *r = range_ptr_init(mrb, NULL, beg, end, excl); - return mrb_range_value(r); -} - -/* - * call-seq: - * rng.first => obj - * rng.begin => obj - * - * Returns the first object in rng. - */ -static mrb_value -range_beg(mrb_state *mrb, mrb_value range) -{ - return mrb_range_beg(mrb, range); -} - -/* - * call-seq: - * rng.end => obj - * rng.last => obj - * - * Returns the object that defines the end of rng. - * - * (1..10).end #=> 10 - * (1...10).end #=> 10 - */ - -static mrb_value -range_end(mrb_state *mrb, mrb_value range) -{ - return mrb_range_end(mrb, range); -} - -/* - * call-seq: - * range.exclude_end? => true or false - * - * Returns true if range excludes its end value. - */ -mrb_value -mrb_range_excl(mrb_state *mrb, mrb_value range) -{ - return mrb_bool_value(mrb_range_excl_p(mrb, range)); -} - -/* - * call-seq: - * Range.new(start, end, exclusive=false) => range - * - * Constructs a range using the given start and end. If the third - * parameter is omitted or is false, the range will include - * the end object; otherwise, it will be excluded. - */ - -mrb_value -mrb_range_initialize(mrb_state *mrb, mrb_value range) -{ - mrb_value beg, end; - mrb_bool exclusive; - mrb_int n; - - n = mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive); - if (n != 3) { - exclusive = FALSE; - } - range_ptr_replace(mrb, mrb_range_raw_ptr(range), beg, end, exclusive); - return range; -} -/* - * call-seq: - * range == obj => true or false - * - * Returns true only if - * 1) obj is a Range, - * 2) obj has equivalent beginning and end items (by comparing them with ==), - * 3) obj has the same #exclude_end? setting as rng. - * - * (0..2) == (0..2) #=> true - * (0..2) == Range.new(0,2) #=> true - * (0..2) == (0...2) #=> false - * - */ - -mrb_value -mrb_range_eq(mrb_state *mrb, mrb_value range) -{ - struct RRange *rr; - struct RRange *ro; - mrb_value obj, v1, v2; - - mrb_get_args(mrb, "o", &obj); - - if (mrb_obj_equal(mrb, range, obj)) return mrb_true_value(); - if (!mrb_obj_is_instance_of(mrb, obj, mrb_obj_class(mrb, range))) { /* same class? */ - return mrb_false_value(); - } - - rr = mrb_range_ptr(mrb, range); - ro = mrb_range_ptr(mrb, obj); - v1 = mrb_funcall(mrb, RANGE_BEG(rr), "==", 1, RANGE_BEG(ro)); - v2 = mrb_funcall(mrb, RANGE_END(rr), "==", 1, RANGE_END(ro)); - if (!mrb_bool(v1) || !mrb_bool(v2) || RANGE_EXCL(rr) != RANGE_EXCL(ro)) { - return mrb_false_value(); - } - return mrb_true_value(); -} - static mrb_bool r_le(mrb_state *mrb, mrb_value a, mrb_value b) { @@ -241,15 +76,154 @@ r_ge(mrb_state *mrb, mrb_value a, mrb_value b) return FALSE; } +static void +range_ptr_alloc_edges(mrb_state *mrb, struct RRange *r) +{ +#ifndef MRB_RANGE_EMBED + r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); +#endif +} + +static struct RRange * +range_ptr_init(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, mrb_bool excl) +{ + r_check(mrb, beg, end); + + if (r) { + if (RANGE_INITIALIZED_P(r)) { + /* Ranges are immutable, so that they should be initialized only once. */ + mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); + } + else { + range_ptr_alloc_edges(mrb, r); + } + } + else { + r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class); + range_ptr_alloc_edges(mrb, r); + } + + RANGE_BEG(r) = beg; + RANGE_END(r) = end; + RANGE_EXCL(r) = excl; + RANGE_INITIALIZED(r); + + return r; +} + +static void +range_ptr_replace(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, mrb_bool excl) +{ + range_ptr_init(mrb, r, beg, end, excl); + mrb_write_barrier(mrb, (struct RBasic*)r); +} + +/* + * call-seq: + * rng.first => obj + * rng.begin => obj + * + * Returns the first object in rng. + */ +static mrb_value +range_beg(mrb_state *mrb, mrb_value range) +{ + return mrb_range_beg(mrb, range); +} + +/* + * call-seq: + * rng.end => obj + * rng.last => obj + * + * Returns the object that defines the end of rng. + * + * (1..10).end #=> 10 + * (1...10).end #=> 10 + */ +static mrb_value +range_end(mrb_state *mrb, mrb_value range) +{ + return mrb_range_end(mrb, range); +} + +/* + * call-seq: + * range.exclude_end? => true or false + * + * Returns true if range excludes its end value. + */ +static mrb_value +range_excl(mrb_state *mrb, mrb_value range) +{ + return mrb_bool_value(mrb_range_excl_p(mrb, range)); +} + +/* + * call-seq: + * Range.new(start, end, exclusive=false) => range + * + * Constructs a range using the given start and end. If the third + * parameter is omitted or is false, the range will include + * the end object; otherwise, it will be excluded. + */ +static mrb_value +range_initialize(mrb_state *mrb, mrb_value range) +{ + mrb_value beg, end; + mrb_bool exclusive = FALSE; + mrb_int n; + + n = mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive); + range_ptr_replace(mrb, mrb_range_raw_ptr(range), beg, end, exclusive); + return range; +} + +/* + * call-seq: + * range == obj => true or false + * + * Returns true only if + * 1) obj is a Range, + * 2) obj has equivalent beginning and end items (by comparing them with ==), + * 3) obj has the same #exclude_end? setting as rng. + * + * (0..2) == (0..2) #=> true + * (0..2) == Range.new(0,2) #=> true + * (0..2) == (0...2) #=> false + */ +static mrb_value +range_eq(mrb_state *mrb, mrb_value range) +{ + struct RRange *rr; + struct RRange *ro; + mrb_value obj, v1, v2; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_obj_equal(mrb, range, obj)) return mrb_true_value(); + if (!mrb_obj_is_instance_of(mrb, obj, mrb_obj_class(mrb, range))) { /* same class? */ + return mrb_false_value(); + } + + rr = mrb_range_ptr(mrb, range); + ro = mrb_range_ptr(mrb, obj); + v1 = mrb_funcall(mrb, RANGE_BEG(rr), "==", 1, RANGE_BEG(ro)); + v2 = mrb_funcall(mrb, RANGE_END(rr), "==", 1, RANGE_END(ro)); + if (!mrb_bool(v1) || !mrb_bool(v2) || RANGE_EXCL(rr) != RANGE_EXCL(ro)) { + return mrb_false_value(); + } + return mrb_true_value(); +} + /* * call-seq: * range === obj => true or false * range.member?(val) => true or false * range.include?(val) => true or false - * */ -mrb_value -mrb_range_include(mrb_state *mrb, mrb_value range) +static mrb_value +range_include(mrb_state *mrb, mrb_value range) { mrb_value val; struct RRange *r = mrb_range_ptr(mrb, range); @@ -267,39 +241,6 @@ mrb_range_include(mrb_state *mrb, mrb_value range) return mrb_bool_value(include_p); } -MRB_API mrb_int -mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) -{ - mrb_int beg, end; - struct RRange *r; - - if (mrb_type(range) != MRB_TT_RANGE) return 0; - r = mrb_range_ptr(mrb, range); - - beg = mrb_int(mrb, RANGE_BEG(r)); - end = mrb_int(mrb, RANGE_END(r)); - - if (beg < 0) { - beg += len; - if (beg < 0) return 2; - } - - if (trunc) { - if (beg > len) return 2; - if (end > len) end = len; - } - - if (end < 0) end += len; - if (!RANGE_EXCL(r) && (!trunc || end < len)) - end++; /* include end point */ - len = end - beg; - if (len < 0) len = 0; - - *begp = beg; - *lenp = len; - return 1; -} - /* 15.2.14.4.12(x) */ /* * call-seq: @@ -307,7 +248,6 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, * * Convert this range object to a printable form. */ - static mrb_value range_to_s(mrb_state *mrb, mrb_value range) { @@ -332,7 +272,6 @@ range_to_s(mrb_state *mrb, mrb_value range) * inspect to convert the start and end * objects). */ - static mrb_value range_inspect(mrb_state *mrb, mrb_value range) { @@ -360,9 +299,7 @@ range_inspect(mrb_state *mrb, mrb_value range) * (0..2).eql?(0..2) #=> true * (0..2).eql?(Range.new(0,2)) #=> true * (0..2).eql?(0...2) #=> false - * */ - static mrb_value range_eql(mrb_state *mrb, mrb_value range) { @@ -372,9 +309,7 @@ range_eql(mrb_state *mrb, mrb_value range) mrb_get_args(mrb, "o", &obj); if (mrb_obj_equal(mrb, range, obj)) return mrb_true_value(); - if (!mrb_obj_is_kind_of(mrb, obj, mrb->range_class)) { - return mrb_false_value(); - } + if (!mrb_obj_is_kind_of(mrb, obj, mrb->range_class)) return mrb_false_value(); if (mrb_type(obj) != MRB_TT_RANGE) return mrb_false_value(); r = mrb_range_ptr(mrb, range); @@ -445,6 +380,57 @@ mrb_gc_mark_range(mrb_state *mrb, struct RRange *r) } } +MRB_API struct RRange* +mrb_range_ptr(mrb_state *mrb, mrb_value range) +{ + struct RRange *r = mrb_range_raw_ptr(range); + + /* check for if #initialize_copy was removed [#3320] */ + if (!RANGE_INITIALIZED_P(r)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range"); + } + return r; +} + +MRB_API mrb_value +mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) +{ + struct RRange *r = range_ptr_init(mrb, NULL, beg, end, excl); + return mrb_range_value(r); +} + +MRB_API mrb_int +mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) +{ + mrb_int beg, end; + struct RRange *r; + + if (mrb_type(range) != MRB_TT_RANGE) return 0; + r = mrb_range_ptr(mrb, range); + + beg = mrb_int(mrb, RANGE_BEG(r)); + end = mrb_int(mrb, RANGE_END(r)); + + if (beg < 0) { + beg += len; + if (beg < 0) return 2; + } + + if (trunc) { + if (beg > len) return 2; + if (end > len) end = len; + } + + if (end < 0) end += len; + if (!RANGE_EXCL(r) && (!trunc || end < len)) end++; /* include end point */ + len = end - beg; + if (len < 0) len = 0; + + *begp = beg; + *lenp = len; + return 1; +} + void mrb_init_range(mrb_state *mrb) { @@ -456,15 +442,14 @@ mrb_init_range(mrb_state *mrb) mrb_define_method(mrb, r, "begin", range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */ mrb_define_method(mrb, r, "end", range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */ - mrb_define_method(mrb, r, "==", mrb_range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */ - mrb_define_method(mrb, r, "===", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */ - mrb_define_method(mrb, r, "exclude_end?", mrb_range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */ + mrb_define_method(mrb, r, "==", range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */ + mrb_define_method(mrb, r, "===", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */ + mrb_define_method(mrb, r, "exclude_end?", range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */ mrb_define_method(mrb, r, "first", range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */ - mrb_define_method(mrb, r, "include?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */ - mrb_define_method(mrb, r, "initialize", mrb_range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */ + mrb_define_method(mrb, r, "include?", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */ + mrb_define_method(mrb, r, "initialize", range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */ mrb_define_method(mrb, r, "last", range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */ - mrb_define_method(mrb, r, "member?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */ - + mrb_define_method(mrb, r, "member?", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */ mrb_define_method(mrb, r, "to_s", range_to_s, MRB_ARGS_NONE()); /* 15.2.14.4.12(x) */ mrb_define_method(mrb, r, "inspect", range_inspect, MRB_ARGS_NONE()); /* 15.2.14.4.13(x) */ mrb_define_method(mrb, r, "eql?", range_eql, MRB_ARGS_REQ(1)); /* 15.2.14.4.14(x) */