diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2019-01-02 11:40:32 +0900 |
|---|---|---|
| committer | GitHub <[email protected]> | 2019-01-02 11:40:32 +0900 |
| commit | 4ffc280372c1e769e271ff9e34d8dace8c9280ac (patch) | |
| tree | 631c9abeed19cc241f3d6e4981379fb00c4b48fe | |
| parent | c6f9a09e393dd5630c59b184a4919311c5c3477b (diff) | |
| parent | 648b57620a6f0bd03ab11db61b1fee343c889dfe (diff) | |
| download | mruby-4ffc280372c1e769e271ff9e34d8dace8c9280ac.tar.gz mruby-4ffc280372c1e769e271ff9e34d8dace8c9280ac.zip | |
Merge pull request #4209 from shuujii/range-embed-edges-in-rrange
range: Embed edges in RRange on boxing environment.
| -rw-r--r-- | include/mruby/range.h | 34 | ||||
| -rw-r--r-- | mrbgems/mruby-range-ext/src/range.c | 15 | ||||
| -rw-r--r-- | src/gc.c | 11 | ||||
| -rw-r--r-- | src/range.c | 161 | ||||
| -rw-r--r-- | test/t/range.rb | 16 |
5 files changed, 147 insertions, 90 deletions
diff --git a/include/mruby/range.h b/include/mruby/range.h index b166e586b..4df5ccc70 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -14,20 +14,43 @@ */ MRB_BEGIN_DECL +#if defined(MRB_NAN_BOXING) || defined(MRB_WORD_BOXING) +# define MRB_RANGE_EMBED +#endif + +#ifdef MRB_RANGE_EMBED +struct RRange { + MRB_OBJECT_HEADER; + mrb_value beg; + mrb_value end; + mrb_bool excl; +}; +# define mrb_gc_free_range(mrb, p) ((void)0) +# define RANGE_BEG(p) ((p)->beg) +# define RANGE_END(p) ((p)->end) +#else typedef struct mrb_range_edges { mrb_value beg; mrb_value end; } mrb_range_edges; - struct RRange { MRB_OBJECT_HEADER; mrb_range_edges *edges; - mrb_bool excl : 1; + mrb_bool excl; }; +# define mrb_gc_free_range(mrb, p) mrb_free(mrb, ((struct RRange*)p)->edges) +# define RANGE_BEG(p) ((p)->edges->beg) +# define RANGE_END(p) ((p)->edges->end) +#endif + +#define mrb_range_beg(mrb, r) RANGE_BEG(mrb_range_ptr(mrb, r)) +#define mrb_range_end(mrb, r) RANGE_END(mrb_range_ptr(mrb, r)) +#define mrb_range_excl_p(mrb, r) RANGE_EXCL(mrb_range_ptr(mrb, r)) +#define mrb_range_raw_ptr(r) ((struct RRange*)mrb_ptr(r)) +#define mrb_range_value(p) mrb_obj_value((void*)(p)) +#define RANGE_EXCL(p) ((p)->excl) -MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value v); -#define mrb_range_raw_ptr(v) ((struct RRange*)mrb_ptr(v)) -#define mrb_range_value(p) mrb_obj_value((void*)(p)) +MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value range); /* * Initializes a Range. @@ -43,6 +66,7 @@ MRB_API mrb_value mrb_range_new(mrb_state *mrb, mrb_value start, mrb_value end, 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_value mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int)); +void mrb_gc_mark_range(mrb_state *mrb, struct RRange *r); MRB_END_DECL diff --git a/mrbgems/mruby-range-ext/src/range.c b/mrbgems/mruby-range-ext/src/range.c index aca71cc01..1fc383755 100644 --- a/mrbgems/mruby-range-ext/src/range.c +++ b/mrbgems/mruby-range-ext/src/range.c @@ -48,11 +48,11 @@ mrb_range_cover(mrb_state *mrb, mrb_value range) mrb_get_args(mrb, "o", &val); - beg = r->edges->beg; - end = r->edges->end; + beg = RANGE_BEG(r); + end = RANGE_END(r); if (r_le(mrb, beg, val)) { - if (r->excl) { + if (RANGE_EXCL(r)) { if (r_lt(mrb, val, end)) return mrb_true_value(); } @@ -86,10 +86,9 @@ mrb_range_last(mrb_state *mrb, mrb_value range) { mrb_value num; mrb_value array; - struct RRange *r = mrb_range_ptr(mrb, range); if (mrb_get_args(mrb, "|o", &num) == 0) { - return r->edges->end; + return mrb_range_end(mrb, range); } array = mrb_funcall(mrb, range, "to_a", 0); @@ -116,9 +115,9 @@ mrb_range_size(mrb_state *mrb, mrb_value range) mrb_bool num_p = TRUE; mrb_bool excl; - beg = r->edges->beg; - end = r->edges->end; - excl = r->excl; + beg = RANGE_BEG(r); + end = RANGE_END(r); + excl = RANGE_EXCL(r); if (mrb_fixnum_p(beg)) { beg_f = (mrb_float)mrb_fixnum(beg); } @@ -739,14 +739,7 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) break; case MRB_TT_RANGE: - { - struct RRange *r = (struct RRange*)obj; - - if (r->edges) { - mrb_gc_mark_value(mrb, r->edges->beg); - mrb_gc_mark_value(mrb, r->edges->end); - } - } + mrb_gc_mark_range(mrb, (struct RRange*)obj); break; default: @@ -870,7 +863,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) break; case MRB_TT_RANGE: - mrb_free(mrb, ((struct RRange*)obj)->edges); + mrb_gc_free_range(mrb, ((struct RRange*)obj)); break; case MRB_TT_DATA: diff --git a/src/range.c b/src/range.c index e45308d35..d2f897bd5 100644 --- a/src/range.c +++ b/src/range.c @@ -10,12 +10,17 @@ #include <mruby/string.h> #include <mruby/array.h> +#define RANGE_INITIALIZED_MASK 1 +#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 v) +mrb_range_ptr(mrb_state *mrb, mrb_value range) { - struct RRange *r = (struct RRange*)mrb_ptr(v); + struct RRange *r = mrb_range_raw_ptr(range); - if (r->edges == NULL) { + /* check for if #initialize_copy was removed [#3320] */ + if (!RANGE_INITIALIZED_P(r)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range"); } return r; @@ -46,17 +51,52 @@ range_check(mrb_state *mrb, mrb_value a, mrb_value b) } } -MRB_API mrb_value -mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) +static void +range_ptr_alloc_edges(mrb_state *mrb, struct RRange *r) { - 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); - r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class); - r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); - r->edges->beg = beg; - r->edges->end = end; - r->excl = excl; + + 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); } @@ -67,12 +107,10 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) * * Returns the first object in <i>rng</i>. */ -mrb_value -mrb_range_beg(mrb_state *mrb, mrb_value range) +static mrb_value +range_beg(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(mrb, range); - - return r->edges->beg; + return mrb_range_beg(mrb, range); } /* @@ -86,12 +124,10 @@ mrb_range_beg(mrb_state *mrb, mrb_value range) * (1...10).end #=> 10 */ -mrb_value -mrb_range_end(mrb_state *mrb, mrb_value range) +static mrb_value +range_end(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(mrb, range); - - return r->edges->end; + return mrb_range_end(mrb, range); } /* @@ -103,25 +139,9 @@ mrb_range_end(mrb_state *mrb, mrb_value range) mrb_value mrb_range_excl(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(mrb, range); - - return mrb_bool_value(r->excl); + return mrb_bool_value(mrb_range_excl_p(mrb, range)); } -static void -range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bool exclude_end) -{ - struct RRange *r = mrb_range_raw_ptr(range); - - range_check(mrb, beg, end); - r->excl = exclude_end; - if (!r->edges) { - r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); - } - r->edges->beg = beg; - r->edges->end = end; - mrb_write_barrier(mrb, (struct RBasic*)r); -} /* * call-seq: * Range.new(start, end, exclusive=false) => range @@ -142,11 +162,7 @@ mrb_range_initialize(mrb_state *mrb, mrb_value range) if (n != 3) { exclusive = FALSE; } - /* Ranges are immutable, so that they should be initialized only once. */ - if (mrb_range_raw_ptr(range)->edges) { - mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); - } - range_init(mrb, range, beg, end, exclusive); + range_ptr_replace(mrb, mrb_range_raw_ptr(range), beg, end, exclusive); return range; } /* @@ -180,9 +196,9 @@ mrb_range_eq(mrb_state *mrb, mrb_value range) rr = mrb_range_ptr(mrb, range); ro = mrb_range_ptr(mrb, obj); - v1 = mrb_funcall(mrb, rr->edges->beg, "==", 1, ro->edges->beg); - v2 = mrb_funcall(mrb, rr->edges->end, "==", 1, ro->edges->end); - if (!mrb_bool(v1) || !mrb_bool(v2) || rr->excl != ro->excl) { + 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(); @@ -242,11 +258,11 @@ mrb_range_include(mrb_state *mrb, mrb_value range) mrb_get_args(mrb, "o", &val); - beg = r->edges->beg; - end = r->edges->end; - include_p = r_le(mrb, beg, val) && /* beg <= val */ - (r->excl ? r_gt(mrb, end, val) /* end > val */ - : r_ge(mrb, end, val)); /* end >= val */ + beg = RANGE_BEG(r); + end = RANGE_END(r); + include_p = r_le(mrb, beg, val) && /* beg <= val */ + (RANGE_EXCL(r) ? r_gt(mrb, end, val) /* end > val */ + : r_ge(mrb, end, val)); /* end >= val */ return mrb_bool_value(include_p); } @@ -260,8 +276,8 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, if (mrb_type(range) != MRB_TT_RANGE) return 0; r = mrb_range_ptr(mrb, range); - beg = mrb_int(mrb, r->edges->beg); - end = mrb_int(mrb, r->edges->end); + beg = mrb_int(mrb, RANGE_BEG(r)); + end = mrb_int(mrb, RANGE_END(r)); if (beg < 0) { beg += len; @@ -274,7 +290,7 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, } if (end < 0) end += len; - if (!r->excl && (!trunc || end < len)) + if (!RANGE_EXCL(r) && (!trunc || end < len)) end++; /* include end point */ len = end - beg; if (len < 0) len = 0; @@ -298,10 +314,10 @@ range_to_s(mrb_state *mrb, mrb_value range) mrb_value str, str2; struct RRange *r = mrb_range_ptr(mrb, range); - str = mrb_obj_as_string(mrb, r->edges->beg); - str2 = mrb_obj_as_string(mrb, r->edges->end); + str = mrb_obj_as_string(mrb, RANGE_BEG(r)); + str2 = mrb_obj_as_string(mrb, RANGE_END(r)); str = mrb_str_dup(mrb, str); - mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); + mrb_str_cat(mrb, str, "...", RANGE_EXCL(r) ? 3 : 2); mrb_str_cat_str(mrb, str, str2); return str; @@ -323,10 +339,10 @@ range_inspect(mrb_state *mrb, mrb_value range) mrb_value str, str2; struct RRange *r = mrb_range_ptr(mrb, range); - str = mrb_inspect(mrb, r->edges->beg); - str2 = mrb_inspect(mrb, r->edges->end); + str = mrb_inspect(mrb, RANGE_BEG(r)); + str2 = mrb_inspect(mrb, RANGE_END(r)); str = mrb_str_dup(mrb, str); - mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); + mrb_str_cat(mrb, str, "...", RANGE_EXCL(r) ? 3 : 2); mrb_str_cat_str(mrb, str, str2); return str; @@ -363,9 +379,9 @@ range_eql(mrb_state *mrb, mrb_value range) r = mrb_range_ptr(mrb, range); o = mrb_range_ptr(mrb, obj); - if (!mrb_eql(mrb, r->edges->beg, o->edges->beg) || - !mrb_eql(mrb, r->edges->end, o->edges->end) || - (r->excl != o->excl)) { + if (!mrb_eql(mrb, RANGE_BEG(r), RANGE_BEG(o)) || + !mrb_eql(mrb, RANGE_END(r), RANGE_END(o)) || + (RANGE_EXCL(r) != RANGE_EXCL(o))) { return mrb_false_value(); } return mrb_true_value(); @@ -386,7 +402,7 @@ range_initialize_copy(mrb_state *mrb, mrb_value copy) } r = mrb_range_ptr(mrb, src); - range_init(mrb, copy, r->edges->beg, r->edges->end, r->excl); + range_ptr_replace(mrb, mrb_range_raw_ptr(copy), RANGE_BEG(r), RANGE_END(r), RANGE_EXCL(r)); return copy; } @@ -421,6 +437,15 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con } void +mrb_gc_mark_range(mrb_state *mrb, struct RRange *r) +{ + if (RANGE_INITIALIZED_P(r)) { + mrb_gc_mark_value(mrb, RANGE_BEG(r)); + mrb_gc_mark_value(mrb, RANGE_END(r)); + } +} + +void mrb_init_range(mrb_state *mrb) { struct RClass *r; @@ -429,15 +454,15 @@ mrb_init_range(mrb_state *mrb) mrb->range_class = r; MRB_SET_INSTANCE_TT(r, MRB_TT_RANGE); - mrb_define_method(mrb, r, "begin", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */ - mrb_define_method(mrb, r, "end", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */ + 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, "first", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */ + 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, "last", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */ + 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, "to_s", range_to_s, MRB_ARGS_NONE()); /* 15.2.14.4.12(x) */ diff --git a/test/t/range.rb b/test/t/range.rb index 5aee4d5cc..64e7f9d9f 100644 --- a/test/t/range.rb +++ b/test/t/range.rb @@ -93,3 +93,19 @@ assert('Range#eql?', '15.2.14.4.14') do assert_false (1..10).eql? (Range.new(1.0, 10.0)) assert_false (1..10).eql? "1..10" end + +assert('Range#initialize_copy', '15.2.14.4.15') do + assert_raise(NameError) { (0..1).__send__(:initialize_copy, 1..3) } +end + +assert('Range#dup') do + r = (1..3).dup + assert_equal r.begin, 1 + assert_equal r.end, 3 + assert_false r.exclude_end? + + r = ("a"..."z").dup + assert_equal r.begin, "a" + assert_equal r.end, "z" + assert_true r.exclude_end? +end |
