Upgrade to 1.46.0
[platform/upstream/nghttp2.git] / third-party / mruby / mrbgems / mruby-range-ext / src / range.c
1 #include <mruby.h>
2 #include <mruby/range.h>
3 #include <math.h>
4
5 static mrb_bool
6 r_le(mrb_state *mrb, mrb_value a, mrb_value b)
7 {
8   mrb_int n = mrb_cmp(mrb, a, b);
9
10   if (n == 0 || n == -1) return TRUE;
11   return FALSE;
12 }
13
14 static mrb_bool
15 r_lt(mrb_state *mrb, mrb_value a, mrb_value b)
16 {
17   return mrb_cmp(mrb, a, b) == -1;
18 }
19
20 /*
21  *  call-seq:
22  *     rng.cover?(obj)  ->  true or false
23  *
24  *  Returns <code>true</code> if +obj+ is between the begin and end of
25  *  the range.
26  *
27  *  This tests <code>begin <= obj <= end</code> when #exclude_end? is +false+
28  *  and <code>begin <= obj < end</code> when #exclude_end? is +true+.
29  *
30  *     ("a".."z").cover?("c")    #=> true
31  *     ("a".."z").cover?("5")    #=> false
32  *     ("a".."z").cover?("cc")   #=> true
33  */
34 static mrb_value
35 range_cover(mrb_state *mrb, mrb_value range)
36 {
37   struct RRange *r = mrb_range_ptr(mrb, range);
38   mrb_value val = mrb_get_arg1(mrb);
39   mrb_value beg, end;
40
41   beg = RANGE_BEG(r);
42   end = RANGE_END(r);
43
44   if (r_le(mrb, beg, val)) {
45     if (RANGE_EXCL(r)) {
46       if (r_lt(mrb, val, end))
47         return mrb_true_value();
48     }
49     else {
50       if (r_le(mrb, val, end))
51         return mrb_true_value();
52     }
53   }
54
55   return mrb_false_value();
56 }
57
58 /*
59  *  call-seq:
60  *     rng.last    -> obj
61  *     rng.last(n) -> an_array
62  *
63  *  Returns the last object in the range,
64  *  or an array of the last +n+ elements.
65  *
66  *  Note that with no arguments +last+ will return the object that defines
67  *  the end of the range even if #exclude_end? is +true+.
68  *
69  *    (10..20).last      #=> 20
70  *    (10...20).last     #=> 20
71  *    (10..20).last(3)   #=> [18, 19, 20]
72  *    (10...20).last(3)  #=> [17, 18, 19]
73  */
74 static mrb_value
75 range_last(mrb_state *mrb, mrb_value range)
76 {
77   mrb_value num;
78   mrb_value array;
79
80   if (mrb_get_args(mrb, "|o", &num) == 0) {
81     return mrb_range_end(mrb, range);
82   }
83
84   array = mrb_funcall(mrb, range, "to_a", 0);
85   return mrb_funcall(mrb, array, "last", 1, mrb_to_int(mrb, num));
86 }
87
88 /*
89  *  call-seq:
90  *     rng.size                   -> num
91  *
92  *  Returns the number of elements in the range. Both the begin and the end of
93  *  the Range must be Numeric, otherwise nil is returned.
94  *
95  *    (10..20).size    #=> 11
96  *    ('a'..'z').size  #=> nil
97  */
98
99 #ifndef MRB_WITHOUT_FLOAT
100 static mrb_value
101 range_size(mrb_state *mrb, mrb_value range)
102 {
103   struct RRange *r = mrb_range_ptr(mrb, range);
104   mrb_value beg, end;
105   mrb_float beg_f, end_f;
106   mrb_bool num_p = TRUE;
107   mrb_bool excl;
108
109   beg = RANGE_BEG(r);
110   end = RANGE_END(r);
111   excl = RANGE_EXCL(r);
112   if (mrb_fixnum_p(beg)) {
113     beg_f = (mrb_float)mrb_fixnum(beg);
114   }
115   else if (mrb_float_p(beg)) {
116     beg_f = mrb_float(beg);
117   }
118   else {
119     num_p = FALSE;
120   }
121   if (mrb_fixnum_p(end)) {
122     end_f = (mrb_float)mrb_fixnum(end);
123   }
124   else if (mrb_float_p(end)) {
125     end_f = mrb_float(end);
126   }
127   else {
128     num_p = FALSE;
129   }
130   if (num_p) {
131     mrb_float n = end_f - beg_f;
132     mrb_float err = (fabs(beg_f) + fabs(end_f) + fabs(end_f-beg_f)) * MRB_FLOAT_EPSILON;
133
134     if (err>0.5) err=0.5;
135     if (excl) {
136       if (n<=0) return mrb_fixnum_value(0);
137       if (n<1)
138         n = 0;
139       else
140         n = floor(n - err);
141     }
142     else {
143       if (n<0) return mrb_fixnum_value(0);
144       n = floor(n + err);
145     }
146     if (isinf(n+1))
147       return mrb_float_value(mrb, INFINITY);
148     return mrb_fixnum_value((mrb_int)n+1);
149   }
150   return mrb_nil_value();
151 }
152 #else
153 static mrb_value
154 range_size(mrb_state *mrb, mrb_value range)
155 {
156   struct RRange *r = mrb_range_ptr(mrb, range);
157   mrb_value beg, end;
158   mrb_int excl;
159
160   beg = RANGE_BEG(r);
161   end = RANGE_END(r);
162   excl = RANGE_EXCL(r) ? 0 : 1;
163
164   if (mrb_fixnum_p(beg) && mrb_fixnum_p(end)) {
165     mrb_int a = mrb_fixnum(beg);
166     mrb_int b = mrb_fixnum(end);
167     mrb_int c = b - a + excl;
168
169     return mrb_fixnum_value(c);
170   }
171   return mrb_nil_value();
172 }
173 #endif /* MRB_WITHOUT_FLOAT */
174
175 void
176 mrb_mruby_range_ext_gem_init(mrb_state* mrb)
177 {
178   struct RClass * s = mrb_class_get(mrb, "Range");
179
180   mrb_define_method(mrb, s, "cover?", range_cover, MRB_ARGS_REQ(1));
181   mrb_define_method(mrb, s, "last",   range_last,  MRB_ARGS_OPT(1));
182   mrb_define_method(mrb, s, "size",   range_size,  MRB_ARGS_NONE());
183 }
184
185 void
186 mrb_mruby_range_ext_gem_final(mrb_state* mrb)
187 {
188 }