mrb_value mrb_range_eq(mrb_state *mrb, mrb_value range) { struct RRange *rr; struct RRange *ro; mrb_value obj; mrb_get_args(mrb, "o", &obj); if (mrb_obj_equal(mrb, range, obj)) return mrb_true_value(); /* same class? */ // if (!rb_obj_is_instance_of(obj, rb_obj_class(range))) if (!mrb_obj_is_instance_of(mrb, obj, mrb_obj_class(mrb, range))) return mrb_false_value(); rr = mrb_range_ptr(range); ro = mrb_range_ptr(obj); if (!mrb_obj_equal(mrb, rr->edges->beg, ro->edges->beg)) return mrb_false_value(); if (!mrb_obj_equal(mrb, rr->edges->end, ro->edges->end)) return mrb_false_value(); if (rr->excl != ro->excl) return mrb_false_value(); return mrb_true_value(); }
/* 15.2.14.4.15(x) */ mrb_value range_initialize_copy(mrb_state *mrb, mrb_value copy) { mrb_value src; mrb_get_args(mrb, "o", &src); if (mrb_obj_equal(mrb, copy, src)) return copy; //mrb_check_frozen(copy); if (!mrb_obj_is_instance_of(mrb, src, mrb_obj_class(mrb, copy))) { mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); } memcpy(mrb_range_ptr(copy), mrb_range_ptr(src), sizeof(struct RRange)); return copy; }
/* 15.2.14.4.15(x) */ mrb_value range_initialize_copy(mrb_state *mrb, mrb_value copy) { mrb_value src; mrb_get_args(mrb, "o", &src); if (mrb_obj_equal(mrb, copy, src)) return copy; if (!mrb_obj_is_instance_of(mrb, src, mrb_obj_class(mrb, copy))) { mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); } *mrb_range_ptr(copy) = *mrb_range_ptr(src); return copy; }
/* * call-seq: * range.exclude_end? => true or false * * Returns <code>true</code> if <i>range</i> excludes its end value. */ mrb_value mrb_range_excl(mrb_state *mrb, mrb_value range) { struct RRange *r = mrb_range_ptr(range); return mrb_bool_value(r->excl); }
static mrb_value recursive_eql(mrb_state *mrb, mrb_value range, mrb_value obj, int recur) { struct RRange *r = mrb_range_ptr(range); struct RRange *o = mrb_range_ptr(obj); if (recur) return mrb_true_value(); /* Subtle! */ if (!mrb_eql(mrb, r->edges->beg, o->edges->beg)) return mrb_false_value(); if (!mrb_eql(mrb, r->edges->end, o->edges->end)) return mrb_false_value(); if (r->excl != o->excl) return mrb_false_value(); return mrb_true_value(); }
MRB_API mrb_bool 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, b, e; struct RRange *r = mrb_range_ptr(range); if (mrb_type(range) != MRB_TT_RANGE) return FALSE; beg = b = mrb_int(mrb, r->edges->beg); end = e = mrb_int(mrb, r->edges->end); if (beg < 0) { beg += len; if (beg < 0) return FALSE; } if (trunc) { if (beg > len) return FALSE; if (end > len) end = len; } if (end < 0) end += len; if (!r->excl && (!trunc || end < len)) end++; /* include end point */ len = end - beg; if (len < 0) len = 0; *begp = beg; *lenp = len; return TRUE; }
/* * call-seq: * rng.cover?(obj) -> true or false * * Returns <code>true</code> if +obj+ is between the begin and end of * the range. * * This tests <code>begin <= obj <= end</code> when #exclude_end? is +false+ * and <code>begin <= obj < end</code> when #exclude_end? is +true+. * * ("a".."z").cover?("c") #=> true * ("a".."z").cover?("5") #=> false * ("a".."z").cover?("cc") #=> true */ static mrb_value mrb_range_cover(mrb_state *mrb, mrb_value range) { mrb_value val; struct RRange *r = mrb_range_ptr(mrb, range); mrb_value beg, end; mrb_get_args(mrb, "o", &val); beg = r->edges->beg; end = r->edges->end; if (r_le(mrb, beg, val)) { if (r->excl) { if (r_lt(mrb, val, end)) return mrb_true_value(); } else { if (r_le(mrb, val, end)) return mrb_true_value(); } } return mrb_false_value(); }
mrb_int mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_int err) { mrb_int beg, end, b, e; struct RRange *r = mrb_range_ptr(range); if (mrb_type(range) != MRB_TT_RANGE) return FALSE; beg = b = mrb_fixnum(r->edges->beg); end = e = mrb_fixnum(r->edges->end); if (beg < 0) { beg += len; if (beg < 0) goto out_of_range; } if (err == 0 || err == 2) { if (beg > len) goto out_of_range; if (end > len) end = len; } if (end < 0) end += len; if (!r->excl) end++; /* include end point */ len = end - beg; if (len < 0) len = 0; *begp = beg; *lenp = len; return TRUE; out_of_range: if (err) { mrb_raise(mrb, E_RANGE_ERROR, "%ld..%s%ld out of range", b, r->excl? "." : "", e); } return OTHER; }
mrb_value mrb_range_end(mrb_state *mrb, mrb_value range) { struct RRange *r = mrb_range_ptr(range); return r->edges->end; }
mrb_int mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len) { mrb_int beg, end, b, e; struct RRange *r = mrb_range_ptr(range); if (mrb_type(range) != MRB_TT_RANGE) { mrb_raise(mrb, E_TYPE_ERROR, "expected Range."); } beg = b = mrb_fixnum(r->edges->beg); end = e = mrb_fixnum(r->edges->end); if (beg < 0) { beg += len; if (beg < 0) return FALSE; } if (beg > len) return FALSE; if (end > len) end = len; if (end < 0) end += len; if (!r->excl && end < len) end++; /* include end point */ len = end - beg; if (len < 0) len = 0; *begp = beg; *lenp = len; return TRUE; }
/* * call-seq: * range.exclude_end? => true or false * * Returns <code>true</code> if <i>range</i> excludes its end value. */ mrb_value mrb_range_excl(mrb_state *mrb, mrb_value range) { struct RRange *r = mrb_range_ptr(range); return r->excl ? mrb_true_value() : mrb_false_value(); }
static void range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_int exclude_end) { struct RRange *r = mrb_range_ptr(range); range_check(mrb, beg, end); r->excl = exclude_end; r->edges->beg = beg; r->edges->end = end; }
static mrb_value mrb_range_size(mrb_state *mrb, mrb_value range) { struct RRange *r = mrb_range_ptr(mrb, range); mrb_value beg, end; mrb_float beg_f, end_f; mrb_bool num_p = TRUE; mrb_bool excl; beg = r->edges->beg; end = r->edges->end; excl = r->excl; if (mrb_fixnum_p(beg)) { beg_f = (mrb_float)mrb_fixnum(beg); } else if (mrb_float_p(beg)) { beg_f = mrb_float(beg); } else { num_p = FALSE; } if (mrb_fixnum_p(end)) { end_f = (mrb_float)mrb_fixnum(end); } else if (mrb_float_p(end)) { end_f = mrb_float(end); } else { num_p = FALSE; } if (num_p) { mrb_float n = end_f - beg_f; mrb_float err = (fabs(beg_f) + fabs(end_f) + fabs(end_f-beg_f)) * MRB_FLOAT_EPSILON; if (err>0.5) err=0.5; if (excl) { if (n<=0) return mrb_fixnum_value(0); if (n<1) n = 0; else n = floor(n - err); } else { if (n<0) return mrb_fixnum_value(0); n = floor(n + err); } if (isinf(n+1)) return mrb_float_value(mrb, INFINITY); return mrb_fixnum_value(n+1); } return mrb_nil_value(); }
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_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_value mrb_range_eq(mrb_state *mrb, mrb_value range) { struct RRange *rr; struct RRange *ro; mrb_value obj; 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(range); ro = mrb_range_ptr(obj); if (!mrb_bool(mrb_funcall(mrb, rr->edges->beg, "==", 1, ro->edges->beg)) || !mrb_bool(mrb_funcall(mrb, rr->edges->end, "==", 1, ro->edges->end)) || rr->excl != ro->excl) { return mrb_false_value(); } return mrb_true_value(); }
/* * call-seq: * rng.last -> obj * rng.last(n) -> an_array * * Returns the last object in the range, * or an array of the last +n+ elements. * * Note that with no arguments +last+ will return the object that defines * the end of the range even if #exclude_end? is +true+. * * (10..20).last #=> 20 * (10...20).last #=> 20 * (10..20).last(3) #=> [18, 19, 20] * (10...20).last(3) #=> [17, 18, 19] */ static mrb_value 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; } array = mrb_funcall(mrb, range, "to_a", 0); return mrb_funcall(mrb, array, "last", 1, mrb_to_int(mrb, num)); }
static mrb_value range_eql(mrb_state *mrb, mrb_value range) { mrb_value obj; struct RRange *r, *o; 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, RANGE_CLASS)) { return mrb_false_value(); } if (mrb_type(obj) != MRB_TT_RANGE) return mrb_false_value(); r = mrb_range_ptr(range); o = mrb_range_ptr(obj); if (!mrb_eql(mrb, r->edges->beg, o->edges->beg) || !mrb_eql(mrb, r->edges->end, o->edges->end) || (r->excl != o->excl)) { return mrb_false_value(); } return mrb_true_value(); }
static mrb_value range_to_s(mrb_state *mrb, mrb_value range) { mrb_value str, str2; struct RRange *r = mrb_range_ptr(range); str = mrb_obj_as_string(mrb, r->edges->beg); str2 = mrb_obj_as_string(mrb, r->edges->end); str = mrb_str_dup(mrb, str); mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); mrb_str_append(mrb, str, str2); return str; }
static mrb_value inspect_range(mrb_state *mrb, mrb_value range, mrb_value dummy, int recur) { mrb_value str, str2; struct RRange *r = mrb_range_ptr(range); if (recur) { return mrb_str_new2(mrb, r->excl ? "(... ... ...)" : "(... .. ...)"); } str = mrb_inspect(mrb, r->edges->beg); str2 = mrb_inspect(mrb, r->edges->end); str = mrb_str_dup(mrb, str); mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); mrb_str_append(mrb, str, str2); return str; }
/* * 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) { mrb_value val; struct RRange *r = mrb_range_ptr(range); mrb_value beg, end; mrb_bool include_p; 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 */ return mrb_bool_value(include_p); }
/* 15.2.14.4.15(x) */ static mrb_value range_initialize_copy(mrb_state *mrb, mrb_value copy) { mrb_value src; struct RRange *r; mrb_get_args(mrb, "o", &src); if (mrb_obj_equal(mrb, copy, src)) return copy; if (!mrb_obj_is_instance_of(mrb, src, mrb_obj_class(mrb, copy))) { mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); } r = mrb_range_ptr(src); range_init(mrb, copy, r->edges->beg, r->edges->end, r->excl); return copy; }
static void range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_int exclude_end) { mrb_value args[2]; struct RRange *r = mrb_range_ptr(range); if ((mrb_type(beg) != MRB_TT_FIXNUM) || (mrb_type(end) != MRB_TT_FIXNUM)) { args[0] = beg; args[1] = end; /* eroor.c v = mrb_rescue(range_check, (mrb_value)args, range_failed, 0); if (mrb_nil_p(v)) range_failed(); */ if (!range_check(mrb, args)) { printf("range_failed()\n"); } } r->excl = exclude_end; r->edges->beg = beg; r->edges->end = end; }
static mrb_value inspect_range(mrb_state *mrb, mrb_value range, mrb_value dummy, int recur) { mrb_value str, str2; struct RRange *r = mrb_range_ptr(range); if (recur) { static const char s[2][14] = { "(... ... ...)", "(... .. ...)" }; static const int n[] = { 13, 12 }; int idx; idx = (r->excl) ? 0 : 1; return mrb_str_new(mrb, s[idx], n[idx]); } str = mrb_inspect(mrb, r->edges->beg); str2 = mrb_inspect(mrb, r->edges->end); str = mrb_str_dup(mrb, str); mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); mrb_str_append(mrb, str, str2); return str; }
/* * 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) { mrb_value val; struct RRange *r = mrb_range_ptr(range); mrb_value beg, end; mrb_get_args(mrb, "o", &val); beg = r->edges->beg; end = r->edges->end; if (r_le(mrb, beg, val)) { /* beg <= val */ if (r->excl) { if (r_gt(mrb, end, val)) return mrb_true_value(); /* end > val */ } else { if (r_ge(mrb, end, val)) return mrb_true_value(); /* end >= val */ } } return mrb_false_value(); }
static mrb_bool is_safe_migratable_simple_value(mrb_state *mrb, mrb_value v, mrb_state *mrb2) { switch (mrb_type(v)) { case MRB_TT_OBJECT: case MRB_TT_EXCEPTION: { struct RObject *o = mrb_obj_ptr(v); mrb_value path = mrb_class_path(mrb, o->c); if (mrb_nil_p(path) || !mrb_class_defined(mrb2, RSTRING_PTR(path))) { return FALSE; } } break; case MRB_TT_FALSE: case MRB_TT_TRUE: case MRB_TT_FIXNUM: case MRB_TT_SYMBOL: case MRB_TT_FLOAT: case MRB_TT_STRING: break; case MRB_TT_RANGE: { struct RRange *r = mrb_range_ptr(v); if (!is_safe_migratable_simple_value(mrb, r->edges->beg, mrb2) || !is_safe_migratable_simple_value(mrb, r->edges->end, mrb2)) { return FALSE; } } break; case MRB_TT_ARRAY: { struct RArray *a0; int i; a0 = mrb_ary_ptr(v); for (i=0; i<a0->len; i++) { if (!is_safe_migratable_simple_value(mrb, a0->ptr[i], mrb2)) { return FALSE; } } } break; case MRB_TT_HASH: { mrb_value ka; int i, l; ka = mrb_hash_keys(mrb, v); l = RARRAY_LEN(ka); for (i = 0; i < l; i++) { mrb_value k = mrb_ary_entry(ka, i); if (!is_safe_migratable_simple_value(mrb, k, mrb2) || !is_safe_migratable_simple_value(mrb, mrb_hash_get(mrb, v, k), mrb2)) { return FALSE; } } } break; case MRB_TT_DATA: if (!is_safe_migratable_datatype(DATA_TYPE(v))) return FALSE; break; default: return FALSE; break; } return TRUE; }
// based on https://gist.github.com/3066997 static mrb_value migrate_simple_value(mrb_state *mrb, mrb_value v, mrb_state *mrb2) { mrb_value nv; switch (mrb_type(v)) { case MRB_TT_OBJECT: case MRB_TT_EXCEPTION: { struct RObject *o = mrb_obj_ptr(v); mrb_value path = mrb_class_path(mrb, o->c); struct RClass *c; if (mrb_nil_p(path)) { mrb_raise(mrb, E_TYPE_ERROR, "cannot migrate class"); } c = mrb_class_get(mrb2, RSTRING_PTR(path)); nv = mrb_obj_value(mrb_obj_alloc(mrb2, mrb_type(v), c)); } migrate_simple_iv(mrb, v, mrb2, nv); break; case MRB_TT_FALSE: case MRB_TT_TRUE: case MRB_TT_FIXNUM: nv = v; break; case MRB_TT_SYMBOL: nv = mrb_symbol_value(migrate_sym(mrb, mrb_symbol(v), mrb2)); break; case MRB_TT_FLOAT: nv = mrb_float_value(mrb2, mrb_float(v)); break; case MRB_TT_STRING: nv = mrb_str_new(mrb2, RSTRING_PTR(v), RSTRING_LEN(v)); break; case MRB_TT_RANGE: { struct RRange *r = mrb_range_ptr(v); nv = mrb_range_new(mrb2, migrate_simple_value(mrb, r->edges->beg, mrb2), migrate_simple_value(mrb, r->edges->end, mrb2), r->excl); } break; case MRB_TT_ARRAY: { struct RArray *a0, *a1; int i; a0 = mrb_ary_ptr(v); nv = mrb_ary_new_capa(mrb2, a0->len); a1 = mrb_ary_ptr(nv); for (i=0; i<a0->len; i++) { int ai = mrb_gc_arena_save(mrb2); a1->ptr[i] = migrate_simple_value(mrb, a0->ptr[i], mrb2); a1->len++; mrb_gc_arena_restore(mrb2, ai); } } break; case MRB_TT_HASH: { mrb_value ka; int i, l; nv = mrb_hash_new(mrb2); ka = mrb_hash_keys(mrb, v); l = RARRAY_LEN(ka); for (i = 0; i < l; i++) { int ai = mrb_gc_arena_save(mrb2); mrb_value k = migrate_simple_value(mrb, mrb_ary_entry(ka, i), mrb2); mrb_value o = migrate_simple_value(mrb, mrb_hash_get(mrb, v, k), mrb2); mrb_hash_set(mrb2, nv, k, o); mrb_gc_arena_restore(mrb2, ai); } } migrate_simple_iv(mrb, v, mrb2, nv); break; case MRB_TT_DATA: if (!is_safe_migratable_datatype(DATA_TYPE(v))) mrb_raise(mrb, E_TYPE_ERROR, "cannot migrate object"); nv = v; DATA_PTR(nv) = DATA_PTR(v); DATA_TYPE(nv) = DATA_TYPE(v); migrate_simple_iv(mrb, v, mrb2, nv); break; default: mrb_raise(mrb, E_TYPE_ERROR, "cannot migrate object"); break; } return nv; }