source: EcnlProtoTool/trunk/mruby-1.2.0/mrbgems/mruby-range-ext/src/range.c@ 321

Last change on this file since 321 was 321, checked in by coas-nagasima, 7 years ago

文字コードを設定

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