sabme ua / mruby-mbed

Dependents:   mruby_mbed_web mirb_mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers range.c Source File

range.c

00001 #include "mruby.h"
00002 #include "mruby/range.h"
00003 #include <math.h>
00004 
00005 static mrb_bool
00006 r_le(mrb_state *mrb, mrb_value a, mrb_value b)
00007 {
00008   mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */
00009   /* output :a < b => -1, a = b =>  0, a > b => +1 */
00010 
00011   if (mrb_fixnum_p(r)) {
00012     mrb_int c = mrb_fixnum(r);
00013     if (c == 0 || c == -1) return TRUE;
00014   }
00015 
00016   return FALSE;
00017 }
00018 
00019 static mrb_bool
00020 r_lt(mrb_state *mrb, mrb_value a, mrb_value b)
00021 {
00022   mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b);
00023   /* output :a < b => -1, a = b =>  0, a > b => +1 */
00024 
00025   return mrb_fixnum_p(r) && mrb_fixnum(r) == -1;
00026 }
00027 
00028 /*
00029  *  call-seq:
00030  *     rng.cover?(obj)  ->  true or false
00031  *
00032  *  Returns <code>true</code> if +obj+ is between the begin and end of
00033  *  the range.
00034  *
00035  *  This tests <code>begin <= obj <= end</code> when #exclude_end? is +false+
00036  *  and <code>begin <= obj < end</code> when #exclude_end? is +true+.
00037  *
00038  *     ("a".."z").cover?("c")    #=> true
00039  *     ("a".."z").cover?("5")    #=> false
00040  *     ("a".."z").cover?("cc")   #=> true
00041  */
00042 static mrb_value
00043 mrb_range_cover(mrb_state *mrb, mrb_value range)
00044 {
00045   mrb_value val;
00046   struct RRange *r = mrb_range_ptr(range);
00047   mrb_value beg, end;
00048 
00049   mrb_get_args(mrb, "o", &val);
00050 
00051   beg = r->edges->beg;
00052   end = r->edges->end;
00053 
00054   if (r_le(mrb, beg, val)) {
00055     if (r->excl) {
00056       if (r_lt(mrb, val, end))
00057         return mrb_true_value();
00058     }
00059     else {
00060       if (r_le(mrb, val, end))
00061         return mrb_true_value();
00062     }
00063   }
00064 
00065   return mrb_false_value();
00066 }
00067 
00068 /*
00069  *  call-seq:
00070  *     rng.first    -> obj
00071  *     rng.first(n) -> an_array
00072  *
00073  *  Returns the first object in the range, or an array of the first +n+
00074  *  elements.
00075  *
00076  *    (10..20).first     #=> 10
00077  *    (10..20).first(3)  #=> [10, 11, 12]
00078  */
00079 static mrb_value
00080 mrb_range_first(mrb_state *mrb, mrb_value range)
00081 {
00082   mrb_int num;
00083   mrb_value array;
00084   struct RRange *r = mrb_range_ptr(range);
00085 
00086   if (mrb_get_args(mrb, "|i", &num) == 0) {
00087     return r->edges->beg;
00088   }
00089 
00090   array = mrb_funcall(mrb, range, "to_a", 0);
00091   return mrb_funcall(mrb, array, "first", 1, mrb_fixnum_value(num));
00092 }
00093 
00094 /*
00095  *  call-seq:
00096  *     rng.last    -> obj
00097  *     rng.last(n) -> an_array
00098  *
00099  *  Returns the last object in the range,
00100  *  or an array of the last +n+ elements.
00101  *
00102  *  Note that with no arguments +last+ will return the object that defines
00103  *  the end of the range even if #exclude_end? is +true+.
00104  *
00105  *    (10..20).last      #=> 20
00106  *    (10...20).last     #=> 20
00107  *    (10..20).last(3)   #=> [18, 19, 20]
00108  *    (10...20).last(3)  #=> [17, 18, 19]
00109  */
00110 static mrb_value
00111 mrb_range_last(mrb_state *mrb, mrb_value range)
00112 {
00113   mrb_value num;
00114   mrb_value array;
00115   struct RRange *r = mrb_range_ptr(range);
00116 
00117   if (mrb_get_args(mrb, "|o", &num) == 0) {
00118     return r->edges->end;
00119   }
00120 
00121   array = mrb_funcall(mrb, range, "to_a", 0);
00122   return mrb_funcall(mrb, array, "last", 1, mrb_to_int(mrb, num));
00123 }
00124 
00125 /*
00126  *  call-seq:
00127  *     rng.size                   -> num
00128  *
00129  *  Returns the number of elements in the range. Both the begin and the end of
00130  *  the Range must be Numeric, otherwise nil is returned.
00131  *
00132  *    (10..20).size    #=> 11
00133  *    ('a'..'z').size  #=> nil
00134  */
00135 
00136 static mrb_value
00137 mrb_range_size(mrb_state *mrb, mrb_value range)
00138 {
00139   struct RRange *r = mrb_range_ptr(range);
00140   mrb_value beg, end;
00141   double beg_f, end_f;
00142   mrb_bool num_p = TRUE;
00143 
00144   beg = r->edges->beg;
00145   end = r->edges->end;
00146   if (mrb_fixnum_p(beg)) {
00147     beg_f = (double)mrb_fixnum(beg);
00148   }
00149   else if (mrb_float_p(beg)) {
00150     beg_f = mrb_float(beg);
00151   }
00152   else {
00153     num_p = FALSE;
00154   }
00155   if (mrb_fixnum_p(end)) {
00156     end_f = (double)mrb_fixnum(end);
00157   }
00158   else if (mrb_float_p(end)) {
00159     end_f = mrb_float(end);
00160   }
00161   else {
00162     num_p = FALSE;
00163   }
00164   if (num_p) {
00165     double f;
00166 
00167     if (beg_f > end_f) return mrb_fixnum_value(0);
00168     f = end_f - beg_f;
00169     if (!r->excl) {
00170       return mrb_fixnum_value((mrb_int)ceil(f + 1));
00171     }
00172     return mrb_fixnum_value((mrb_int)ceil(f));
00173   }
00174   return mrb_nil_value();
00175 }
00176 
00177 void
00178 mrb_mruby_range_ext_gem_init(mrb_state* mrb)
00179 {
00180   struct RClass * s = mrb_class_get(mrb, "Range");
00181 
00182   mrb_define_method(mrb, s, "cover?", mrb_range_cover, MRB_ARGS_REQ(1));
00183   mrb_define_method(mrb, s, "first",  mrb_range_first, MRB_ARGS_OPT(1));
00184   mrb_define_method(mrb, s, "last",   mrb_range_last,  MRB_ARGS_OPT(1));
00185   mrb_define_method(mrb, s, "size",   mrb_range_size,  MRB_ARGS_NONE());
00186 }
00187 
00188 void
00189 mrb_mruby_range_ext_gem_final(mrb_state* mrb)
00190 {
00191 }
00192