mbed I/F binding for mruby
Dependents: mruby_mbed_web mirb_mbed
range.c
00001 /* 00002 ** range.c - Range class 00003 ** 00004 ** See Copyright Notice in mruby.h 00005 */ 00006 00007 #include "mruby.h" 00008 #include "mruby/class.h" 00009 #include "mruby/range.h" 00010 #include "mruby/string.h" 00011 #include "mruby/array.h" 00012 00013 #define RANGE_CLASS (mrb_class_get(mrb, "Range")) 00014 00015 static void 00016 range_check(mrb_state *mrb, mrb_value a, mrb_value b) 00017 { 00018 mrb_value ans; 00019 enum mrb_vtype ta; 00020 enum mrb_vtype tb; 00021 00022 ta = mrb_type(a); 00023 tb = mrb_type(b); 00024 if ((ta == MRB_TT_FIXNUM || ta == MRB_TT_FLOAT) && 00025 (tb == MRB_TT_FIXNUM || tb == MRB_TT_FLOAT)) { 00026 return; 00027 } 00028 00029 ans = mrb_funcall(mrb, a, "<=>", 1, b); 00030 if (mrb_nil_p(ans)) { 00031 /* can not be compared */ 00032 mrb_raise(mrb, E_ARGUMENT_ERROR, "bad value for range"); 00033 } 00034 } 00035 00036 MRB_API mrb_value 00037 mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) 00038 { 00039 struct RRange *r; 00040 00041 range_check(mrb, beg, end); 00042 r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, RANGE_CLASS); 00043 r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); 00044 r->edges->beg = beg; 00045 r->edges->end = end; 00046 r->excl = excl; 00047 return mrb_range_value(r); 00048 } 00049 00050 /* 00051 * call-seq: 00052 * rng.first => obj 00053 * rng.begin => obj 00054 * 00055 * Returns the first object in <i>rng</i>. 00056 */ 00057 mrb_value 00058 mrb_range_beg(mrb_state *mrb, mrb_value range) 00059 { 00060 struct RRange *r = mrb_range_ptr(range); 00061 00062 return r->edges->beg; 00063 } 00064 00065 /* 00066 * call-seq: 00067 * rng.end => obj 00068 * rng.last => obj 00069 * 00070 * Returns the object that defines the end of <i>rng</i>. 00071 * 00072 * (1..10).end #=> 10 00073 * (1...10).end #=> 10 00074 */ 00075 00076 mrb_value 00077 mrb_range_end(mrb_state *mrb, mrb_value range) 00078 { 00079 struct RRange *r = mrb_range_ptr(range); 00080 00081 return r->edges->end; 00082 } 00083 00084 /* 00085 * call-seq: 00086 * range.exclude_end? => true or false 00087 * 00088 * Returns <code>true</code> if <i>range</i> excludes its end value. 00089 */ 00090 mrb_value 00091 mrb_range_excl(mrb_state *mrb, mrb_value range) 00092 { 00093 struct RRange *r = mrb_range_ptr(range); 00094 00095 return mrb_bool_value(r->excl); 00096 } 00097 00098 static void 00099 range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bool exclude_end) 00100 { 00101 struct RRange *r = mrb_range_ptr(range); 00102 00103 range_check(mrb, beg, end); 00104 r->excl = exclude_end; 00105 if (!r->edges) { 00106 r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); 00107 } 00108 r->edges->beg = beg; 00109 r->edges->end = end; 00110 } 00111 /* 00112 * call-seq: 00113 * Range.new(start, end, exclusive=false) => range 00114 * 00115 * Constructs a range using the given <i>start</i> and <i>end</i>. If the third 00116 * parameter is omitted or is <code>false</code>, the <i>range</i> will include 00117 * the end object; otherwise, it will be excluded. 00118 */ 00119 00120 mrb_value 00121 mrb_range_initialize(mrb_state *mrb, mrb_value range) 00122 { 00123 mrb_value beg, end; 00124 mrb_bool exclusive; 00125 int n; 00126 00127 n = mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive); 00128 if (n != 3) { 00129 exclusive = FALSE; 00130 } 00131 /* Ranges are immutable, so that they should be initialized only once. */ 00132 range_init(mrb, range, beg, end, exclusive); 00133 return range; 00134 } 00135 /* 00136 * call-seq: 00137 * range == obj => true or false 00138 * 00139 * Returns <code>true</code> only if 00140 * 1) <i>obj</i> is a Range, 00141 * 2) <i>obj</i> has equivalent beginning and end items (by comparing them with <code>==</code>), 00142 * 3) <i>obj</i> has the same #exclude_end? setting as <i>rng</t>. 00143 * 00144 * (0..2) == (0..2) #=> true 00145 * (0..2) == Range.new(0,2) #=> true 00146 * (0..2) == (0...2) #=> false 00147 * 00148 */ 00149 00150 mrb_value 00151 mrb_range_eq(mrb_state *mrb, mrb_value range) 00152 { 00153 struct RRange *rr; 00154 struct RRange *ro; 00155 mrb_value obj; 00156 00157 mrb_get_args(mrb, "o", &obj); 00158 00159 if (mrb_obj_equal(mrb, range, obj)) return mrb_true_value(); 00160 if (!mrb_obj_is_instance_of(mrb, obj, mrb_obj_class(mrb, range))) { /* same class? */ 00161 return mrb_false_value(); 00162 } 00163 00164 rr = mrb_range_ptr(range); 00165 ro = mrb_range_ptr(obj); 00166 if (!mrb_bool(mrb_funcall(mrb, rr->edges->beg, "==", 1, ro->edges->beg)) || 00167 !mrb_bool(mrb_funcall(mrb, rr->edges->end, "==", 1, ro->edges->end)) || 00168 rr->excl != ro->excl) { 00169 return mrb_false_value(); 00170 } 00171 return mrb_true_value(); 00172 } 00173 00174 static mrb_bool 00175 r_le(mrb_state *mrb, mrb_value a, mrb_value b) 00176 { 00177 mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ 00178 /* output :a < b => -1, a = b => 0, a > b => +1 */ 00179 00180 if (mrb_fixnum_p(r)) { 00181 mrb_int c = mrb_fixnum(r); 00182 if (c == 0 || c == -1) return TRUE; 00183 } 00184 00185 return FALSE; 00186 } 00187 00188 static mrb_bool 00189 r_gt(mrb_state *mrb, mrb_value a, mrb_value b) 00190 { 00191 mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); 00192 /* output :a < b => -1, a = b => 0, a > b => +1 */ 00193 00194 return mrb_fixnum_p(r) && mrb_fixnum(r) == 1; 00195 } 00196 00197 static mrb_bool 00198 r_ge(mrb_state *mrb, mrb_value a, mrb_value b) 00199 { 00200 mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ 00201 /* output :a < b => -1, a = b => 0, a > b => +1 */ 00202 00203 if (mrb_fixnum_p(r)) { 00204 mrb_int c = mrb_fixnum(r); 00205 if (c == 0 || c == 1) return TRUE; 00206 } 00207 00208 return FALSE; 00209 } 00210 00211 /* 00212 * call-seq: 00213 * range === obj => true or false 00214 * range.member?(val) => true or false 00215 * range.include?(val) => true or false 00216 * 00217 */ 00218 mrb_value 00219 mrb_range_include(mrb_state *mrb, mrb_value range) 00220 { 00221 mrb_value val; 00222 struct RRange *r = mrb_range_ptr(range); 00223 mrb_value beg, end; 00224 mrb_bool include_p; 00225 00226 mrb_get_args(mrb, "o", &val); 00227 00228 beg = r->edges->beg; 00229 end = r->edges->end; 00230 include_p = r_le(mrb, beg, val) && /* beg <= val */ 00231 ((r->excl && r_gt(mrb, end, val)) || /* end > val */ 00232 (r_ge(mrb, end, val))); /* end >= val */ 00233 00234 return mrb_bool_value(include_p); 00235 } 00236 00237 static mrb_bool 00238 range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) 00239 { 00240 mrb_int beg, end; 00241 struct RRange *r = mrb_range_ptr(range); 00242 00243 if (mrb_type(range) != MRB_TT_RANGE) return FALSE; 00244 00245 beg = mrb_int(mrb, r->edges->beg); 00246 end = mrb_int(mrb, r->edges->end); 00247 00248 if (beg < 0) { 00249 beg += len; 00250 if (beg < 0) return FALSE; 00251 } 00252 00253 if (trunc) { 00254 if (beg > len) return FALSE; 00255 if (end > len) end = len; 00256 } 00257 00258 if (end < 0) end += len; 00259 if (!r->excl && (!trunc || end < len)) 00260 end++; /* include end point */ 00261 len = end - beg; 00262 if (len < 0) len = 0; 00263 00264 *begp = beg; 00265 *lenp = len; 00266 return TRUE; 00267 } 00268 00269 MRB_API mrb_bool 00270 mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len) 00271 { 00272 return range_beg_len(mrb, range, begp, lenp, len, TRUE); 00273 } 00274 00275 /* 15.2.14.4.12(x) */ 00276 /* 00277 * call-seq: 00278 * rng.to_s -> string 00279 * 00280 * Convert this range object to a printable form. 00281 */ 00282 00283 static mrb_value 00284 range_to_s(mrb_state *mrb, mrb_value range) 00285 { 00286 mrb_value str, str2; 00287 struct RRange *r = mrb_range_ptr(range); 00288 00289 str = mrb_obj_as_string(mrb, r->edges->beg); 00290 str2 = mrb_obj_as_string(mrb, r->edges->end); 00291 str = mrb_str_dup(mrb, str); 00292 mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); 00293 mrb_str_append(mrb, str, str2); 00294 00295 return str; 00296 } 00297 00298 /* 15.2.14.4.13(x) */ 00299 /* 00300 * call-seq: 00301 * rng.inspect -> string 00302 * 00303 * Convert this range object to a printable form (using 00304 * <code>inspect</code> to convert the start and end 00305 * objects). 00306 */ 00307 00308 static mrb_value 00309 range_inspect(mrb_state *mrb, mrb_value range) 00310 { 00311 mrb_value str, str2; 00312 struct RRange *r = mrb_range_ptr(range); 00313 00314 str = mrb_inspect(mrb, r->edges->beg); 00315 str2 = mrb_inspect(mrb, r->edges->end); 00316 str = mrb_str_dup(mrb, str); 00317 mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); 00318 mrb_str_append(mrb, str, str2); 00319 00320 return str; 00321 } 00322 00323 /* 15.2.14.4.14(x) */ 00324 /* 00325 * call-seq: 00326 * rng.eql?(obj) -> true or false 00327 * 00328 * Returns <code>true</code> only if <i>obj</i> is a Range, has equivalent 00329 * beginning and end items (by comparing them with #eql?), and has the same 00330 * #exclude_end? setting as <i>rng</i>. 00331 * 00332 * (0..2).eql?(0..2) #=> true 00333 * (0..2).eql?(Range.new(0,2)) #=> true 00334 * (0..2).eql?(0...2) #=> false 00335 * 00336 */ 00337 00338 static mrb_value 00339 range_eql(mrb_state *mrb, mrb_value range) 00340 { 00341 mrb_value obj; 00342 struct RRange *r, *o; 00343 00344 mrb_get_args(mrb, "o", &obj); 00345 00346 if (mrb_obj_equal(mrb, range, obj)) return mrb_true_value(); 00347 if (!mrb_obj_is_kind_of(mrb, obj, RANGE_CLASS)) { 00348 return mrb_false_value(); 00349 } 00350 if (mrb_type(obj) != MRB_TT_RANGE) return mrb_false_value(); 00351 00352 r = mrb_range_ptr(range); 00353 o = mrb_range_ptr(obj); 00354 if (!mrb_eql(mrb, r->edges->beg, o->edges->beg) || 00355 !mrb_eql(mrb, r->edges->end, o->edges->end) || 00356 (r->excl != o->excl)) { 00357 return mrb_false_value(); 00358 } 00359 return mrb_true_value(); 00360 } 00361 00362 /* 15.2.14.4.15(x) */ 00363 static mrb_value 00364 range_initialize_copy(mrb_state *mrb, mrb_value copy) 00365 { 00366 mrb_value src; 00367 struct RRange *r; 00368 00369 mrb_get_args(mrb, "o", &src); 00370 00371 if (mrb_obj_equal(mrb, copy, src)) return copy; 00372 if (!mrb_obj_is_instance_of(mrb, src, mrb_obj_class(mrb, copy))) { 00373 mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); 00374 } 00375 00376 r = mrb_range_ptr(src); 00377 range_init(mrb, copy, r->edges->beg, r->edges->end, r->excl); 00378 00379 return copy; 00380 } 00381 00382 mrb_value 00383 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)) 00384 { 00385 mrb_int i, j, beg, len; 00386 mrb_value result; 00387 result = mrb_ary_new(mrb); 00388 00389 for (i = 0; i < argc; ++i) { 00390 if (mrb_fixnum_p(argv[i])) { 00391 mrb_ary_push(mrb, result, func(mrb, obj, mrb_fixnum(argv[i]))); 00392 } 00393 else if (range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE)) { 00394 mrb_int const end = olen < beg + len ? olen : beg + len; 00395 for (j = beg; j < end; ++j) { 00396 mrb_ary_push(mrb, result, func(mrb, obj, j)); 00397 } 00398 00399 for (; j < beg + len; ++j) { 00400 mrb_ary_push(mrb, result, mrb_nil_value()); 00401 } 00402 } 00403 else { 00404 mrb_raisef(mrb, E_TYPE_ERROR, "invalid values selector: %S", argv[i]); 00405 } 00406 } 00407 00408 return result; 00409 } 00410 00411 void 00412 mrb_init_range(mrb_state *mrb) 00413 { 00414 struct RClass *r; 00415 00416 r = mrb_define_class(mrb, "Range", mrb->object_class); /* 15.2.14 */ 00417 MRB_SET_INSTANCE_TT(r, MRB_TT_RANGE); 00418 00419 mrb_define_method(mrb, r, "begin", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */ 00420 mrb_define_method(mrb, r, "end", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */ 00421 mrb_define_method(mrb, r, "==", mrb_range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */ 00422 mrb_define_method(mrb, r, "===", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */ 00423 mrb_define_method(mrb, r, "exclude_end?", mrb_range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */ 00424 mrb_define_method(mrb, r, "first", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */ 00425 mrb_define_method(mrb, r, "include?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */ 00426 mrb_define_method(mrb, r, "initialize", mrb_range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */ 00427 mrb_define_method(mrb, r, "last", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */ 00428 mrb_define_method(mrb, r, "member?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */ 00429 00430 mrb_define_method(mrb, r, "to_s", range_to_s, MRB_ARGS_NONE()); /* 15.2.14.4.12(x) */ 00431 mrb_define_method(mrb, r, "inspect", range_inspect, MRB_ARGS_NONE()); /* 15.2.14.4.13(x) */ 00432 mrb_define_method(mrb, r, "eql?", range_eql, MRB_ARGS_REQ(1)); /* 15.2.14.4.14(x) */ 00433 mrb_define_method(mrb, r, "initialize_copy", range_initialize_copy, MRB_ARGS_REQ(1)); /* 15.2.14.4.15(x) */ 00434 } 00435
Generated on Tue Jul 12 2022 18:00:35 by 1.7.2