aboutsummaryrefslogtreecommitdiffstats
path: root/range.c
diff options
context:
space:
mode:
Diffstat (limited to 'range.c')
-rw-r--r--range.c136
1 files changed, 100 insertions, 36 deletions
diff --git a/range.c b/range.c
index 934f56b7a2..41c1cf088b 100644
--- a/range.c
+++ b/range.c
@@ -15,8 +15,32 @@
VALUE rb_cRange;
static ID id_cmp, id_succ, id_beg, id_end, id_excl;
-#define EXCL(r) RTEST(rb_ivar_get((r), id_excl))
-#define SET_EXCL(r,v) rb_ivar_set((r), id_excl, (v) ? Qtrue : Qfalse)
+#define RANGE_BEG(r) (RSTRUCT(r)->as.ary[0])
+#define RANGE_END(r) (RSTRUCT(r)->as.ary[1])
+#define RANGE_EXCL(r) (RSTRUCT(r)->as.ary[2])
+
+#define EXCL(r) RTEST(RANGE_EXCL(r))
+#define SET_EXCL(r,v) (RSTRUCT(r)->as.ary[2] = (v) ? Qtrue : Qfalse)
+
+#define FL_INITIALIZED FL_USER3
+
+static VALUE
+range_alloc(VALUE klass)
+{
+ long n;
+ NEWOBJ(r, struct RStruct);
+ OBJSETUP(r, klass, T_STRUCT);
+
+ n = 3;
+
+ RBASIC(r)->flags &= ~RSTRUCT_EMBED_LEN_MASK;
+ RBASIC(r)->flags |= n << RSTRUCT_EMBED_LEN_SHIFT;
+ rb_mem_clear(r->as.ary, n);
+
+ RBASIC(r)->flags &= ~FL_INITIALIZED;
+
+ return (VALUE)r;
+}
static VALUE
range_failed(void)
@@ -48,8 +72,8 @@ range_init(VALUE range, VALUE beg, VALUE end, int exclude_end)
}
SET_EXCL(range, exclude_end);
- rb_ivar_set(range, id_beg, beg);
- rb_ivar_set(range, id_end, end);
+ RSTRUCT(range)->as.ary[0] = beg;
+ RSTRUCT(range)->as.ary[1] = end;
}
VALUE
@@ -77,9 +101,10 @@ range_initialize(int argc, VALUE *argv, VALUE range)
rb_scan_args(argc, argv, "21", &beg, &end, &flags);
/* Ranges are immutable, so that they should be initialized only once. */
- if (rb_ivar_defined(range, id_beg)) {
+ if (RBASIC(range)->flags & FL_INITIALIZED) {
rb_name_error(rb_intern("initialize"), "`initialize' called twice");
}
+ RBASIC(range)->flags |= FL_INITIALIZED;
range_init(range, beg, end, RTEST(flags));
return Qnil;
}
@@ -121,9 +146,9 @@ range_eq(VALUE range, VALUE obj)
if (!rb_obj_is_instance_of(obj, rb_obj_class(range)))
return Qfalse;
- if (!rb_equal(rb_ivar_get(range, id_beg), rb_ivar_get(obj, id_beg)))
+ if (!rb_equal(RANGE_BEG(range), RANGE_BEG(obj)))
return Qfalse;
- if (!rb_equal(rb_ivar_get(range, id_end), rb_ivar_get(obj, id_end)))
+ if (!rb_equal(RANGE_END(range), RANGE_END(obj)))
return Qfalse;
if (EXCL(range) != EXCL(obj))
@@ -183,9 +208,9 @@ range_eql(VALUE range, VALUE obj)
if (!rb_obj_is_instance_of(obj, rb_obj_class(range)))
return Qfalse;
- if (!rb_eql(rb_ivar_get(range, id_beg), rb_ivar_get(obj, id_beg)))
+ if (!rb_eql(RANGE_BEG(range), RANGE_BEG(obj)))
return Qfalse;
- if (!rb_eql(rb_ivar_get(range, id_end), rb_ivar_get(obj, id_end)))
+ if (!rb_eql(RANGE_END(range), RANGE_END(obj)))
return Qfalse;
if (EXCL(range) != EXCL(obj))
@@ -209,9 +234,9 @@ range_hash(VALUE range)
long hash = EXCL(range);
VALUE v;
- v = rb_hash(rb_ivar_get(range, id_beg));
+ v = rb_hash(RANGE_BEG(range));
hash ^= v << 1;
- v = rb_hash(rb_ivar_get(range, id_end));
+ v = rb_hash(RANGE_END(range));
hash ^= v << 9;
hash ^= EXCL(range) << 24;
@@ -289,8 +314,8 @@ range_step(int argc, VALUE *argv, VALUE range)
RETURN_ENUMERATOR(range, argc, argv);
- b = rb_ivar_get(range, id_beg);
- e = rb_ivar_get(range, id_end);
+ b = RANGE_BEG(range);
+ e = RANGE_END(range);
if (rb_scan_args(argc, argv, "01", &step) == 0) {
step = INT2FIX(1);
}
@@ -382,8 +407,8 @@ range_each(VALUE range)
RETURN_ENUMERATOR(range, 0, 0);
- beg = rb_ivar_get(range, id_beg);
- end = rb_ivar_get(range, id_end);
+ beg = RANGE_BEG(range);
+ end = RANGE_END(range);
if (!rb_respond_to(beg, id_succ)) {
rb_raise(rb_eTypeError, "can't iterate from %s",
@@ -423,7 +448,7 @@ range_each(VALUE range)
static VALUE
range_first(VALUE range)
{
- return rb_ivar_get(range, id_beg);
+ return RANGE_BEG(range);
}
@@ -442,7 +467,7 @@ range_first(VALUE range)
static VALUE
range_last(VALUE range)
{
- return rb_ivar_get(range, id_end);
+ return RANGE_END(range);
}
/*
@@ -464,8 +489,8 @@ range_min(VALUE range)
return rb_call_super(0, 0);
}
else {
- VALUE b = rb_ivar_get(range, id_beg);
- VALUE e = rb_ivar_get(range, id_end);
+ VALUE b = RANGE_BEG(range);
+ VALUE e = RANGE_END(range);
int c = rb_cmpint(rb_funcall(b, id_cmp, 1, e), b, e);
if (c > 0 || (c == 0 && EXCL(range)))
@@ -489,14 +514,14 @@ range_min(VALUE range)
static VALUE
range_max(VALUE range)
{
- VALUE e = rb_ivar_get(range, id_end);
+ VALUE e = RANGE_END(range);
int ip = FIXNUM_P(e) || rb_obj_is_kind_of(e, rb_cInteger);
if (rb_block_given_p() || (EXCL(range) && !ip)) {
return rb_call_super(0, 0);
}
else {
- VALUE b = rb_ivar_get(range, id_beg);
+ VALUE b = RANGE_BEG(range);
int c = rb_cmpint(rb_funcall(b, id_cmp, 1, e), b, e);
if (c > 0)
@@ -519,8 +544,8 @@ rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
long beg, end, excl;
if (rb_obj_is_kind_of(range, rb_cRange)) {
- b = rb_ivar_get(range, id_beg);
- e = rb_ivar_get(range, id_end);
+ b = RANGE_BEG(range);
+ e = RANGE_END(range);
excl = EXCL(range);
}
else {
@@ -578,8 +603,8 @@ range_to_s(VALUE range)
{
VALUE str, str2;
- str = rb_obj_as_string(rb_ivar_get(range, id_beg));
- str2 = rb_obj_as_string(rb_ivar_get(range, id_end));
+ str = rb_obj_as_string(RANGE_BEG(range));
+ str2 = rb_obj_as_string(RANGE_END(range));
str = rb_str_dup(str);
rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
rb_str_append(str, str2);
@@ -616,8 +641,8 @@ range_inspect(VALUE range)
{
VALUE str, str2;
- str = rb_inspect(rb_ivar_get(range, id_beg));
- str2 = rb_inspect(rb_ivar_get(range, id_end));
+ str = rb_inspect(RANGE_BEG(range));
+ str2 = rb_inspect(RANGE_END(range));
str = rb_str_dup(str);
rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
rb_str_append(str, str2);
@@ -668,8 +693,8 @@ range_eqq(VALUE range, VALUE val)
static VALUE
range_include(VALUE range, VALUE val)
{
- VALUE beg = rb_ivar_get(range, id_beg);
- VALUE end = rb_ivar_get(range, id_end);
+ VALUE beg = RANGE_BEG(range);
+ VALUE end = RANGE_END(range);
int nv = FIXNUM_P(beg) || FIXNUM_P(end) ||
rb_obj_is_kind_of(beg, rb_cNumeric) ||
rb_obj_is_kind_of(end, rb_cNumeric);
@@ -711,8 +736,8 @@ range_cover(VALUE range, VALUE val)
{
VALUE beg, end;
- beg = rb_ivar_get(range, id_beg);
- end = rb_ivar_get(range, id_end);
+ beg = RANGE_BEG(range);
+ end = RANGE_END(range);
if (r_le(beg, val)) {
if (EXCL(range)) {
if (r_lt(val, end))
@@ -726,6 +751,33 @@ range_cover(VALUE range, VALUE val)
return Qfalse;
}
+static VALUE
+range_dumper(VALUE range)
+{
+ VALUE v;
+ NEWOBJ(m, struct RObject);
+ OBJSETUP(m, rb_cObject, T_OBJECT);
+
+ v = (VALUE)m;
+
+ rb_ivar_set(v, id_excl, EXCL(range) ? Qtrue : Qfalse);
+ rb_ivar_set(v, id_beg, RANGE_BEG(range));
+ rb_ivar_set(v, id_end, RANGE_END(range));
+ return v;
+}
+
+static VALUE
+range_loader(VALUE range, VALUE obj)
+{
+ if (TYPE(obj) != T_OBJECT || RBASIC(obj)->klass != rb_cObject) {
+ rb_raise(rb_eTypeError, "not a dumped range object");
+ }
+
+ RSTRUCT(range)->as.ary[0] = rb_ivar_get(obj, id_beg);
+ RSTRUCT(range)->as.ary[1] = rb_ivar_get(obj, id_end);
+ SET_EXCL(range, RTEST(rb_ivar_get(obj, id_excl)));
+ return range;
+}
/* A <code>Range</code> represents an interval---a set of values with a
* start and an end. Ranges may be constructed using the
@@ -782,8 +834,25 @@ range_cover(VALUE range, VALUE val)
void
Init_Range(void)
{
+ VALUE members;
+
+ id_cmp = rb_intern("<=>");
+ id_succ = rb_intern("succ");
+ id_beg = rb_intern("begin");
+ id_end = rb_intern("end");
+ id_excl = rb_intern("excl");
+
rb_cRange = rb_define_class("Range", rb_cObject);
+
+ /* compatibility for rb_struct_members, etc. */
+ members = rb_ary_new3(3, ID2SYM(id_beg), ID2SYM(id_end), ID2SYM(id_excl));
+ OBJ_FREEZE(members);
+ rb_iv_set(rb_cRange, "__size__", INT2FIX(3));
+ rb_iv_set(rb_cRange, "__members__", members);
+
+ rb_define_alloc_func(rb_cRange, range_alloc);
rb_include_module(rb_cRange, rb_mEnumerable);
+ rb_marshal_define_compat(rb_cRange, rb_cObject, range_dumper, range_loader);
rb_define_method(rb_cRange, "initialize", range_initialize, -1);
rb_define_method(rb_cRange, "==", range_eq, 1);
rb_define_method(rb_cRange, "===", range_eqq, 1);
@@ -807,9 +876,4 @@ Init_Range(void)
rb_define_method(rb_cRange, "include?", range_include, 1);
rb_define_method(rb_cRange, "cover?", range_cover, 1);
- id_cmp = rb_intern("<=>");
- id_succ = rb_intern("succ");
- id_beg = rb_intern("begin");
- id_end = rb_intern("end");
- id_excl = rb_intern("excl");
}