source: EcnlProtoTool/trunk/mruby-1.2.0/src/range.c@ 270

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

mruby版ECNLプロトタイピング・ツールを追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 11.1 KB
Line 
1/*
2** range.c - Range class
3**
4** See Copyright Notice in mruby.h
5*/
6
7#include "mruby.h"
8#include "mruby/class.h"
9#include "mruby/range.h"
10#include "mruby/string.h"
11#include "mruby/array.h"
12
13#define RANGE_CLASS (mrb_class_get(mrb, "Range"))
14
15static void
16range_check(mrb_state *mrb, mrb_value a, mrb_value b)
17{
18 mrb_value ans;
19 enum mrb_vtype ta;
20 enum mrb_vtype tb;
21
22 ta = mrb_type(a);
23 tb = mrb_type(b);
24 if ((ta == MRB_TT_FIXNUM || ta == MRB_TT_FLOAT) &&
25 (tb == MRB_TT_FIXNUM || tb == MRB_TT_FLOAT)) {
26 return;
27 }
28
29 ans = mrb_funcall(mrb, a, "<=>", 1, b);
30 if (mrb_nil_p(ans)) {
31 /* can not be compared */
32 mrb_raise(mrb, E_ARGUMENT_ERROR, "bad value for range");
33 }
34}
35
36MRB_API mrb_value
37mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl)
38{
39 struct RRange *r;
40
41 range_check(mrb, beg, end);
42 r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, RANGE_CLASS);
43 r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges));
44 r->edges->beg = beg;
45 r->edges->end = end;
46 r->excl = excl;
47 return mrb_range_value(r);
48}
49
50/*
51 * call-seq:
52 * rng.first => obj
53 * rng.begin => obj
54 *
55 * Returns the first object in <i>rng</i>.
56 */
57mrb_value
58mrb_range_beg(mrb_state *mrb, mrb_value range)
59{
60 struct RRange *r = mrb_range_ptr(range);
61
62 return r->edges->beg;
63}
64
65/*
66 * call-seq:
67 * rng.end => obj
68 * rng.last => obj
69 *
70 * Returns the object that defines the end of <i>rng</i>.
71 *
72 * (1..10).end #=> 10
73 * (1...10).end #=> 10
74 */
75
76mrb_value
77mrb_range_end(mrb_state *mrb, mrb_value range)
78{
79 struct RRange *r = mrb_range_ptr(range);
80
81 return r->edges->end;
82}
83
84/*
85 * call-seq:
86 * range.exclude_end? => true or false
87 *
88 * Returns <code>true</code> if <i>range</i> excludes its end value.
89 */
90mrb_value
91mrb_range_excl(mrb_state *mrb, mrb_value range)
92{
93 struct RRange *r = mrb_range_ptr(range);
94
95 return mrb_bool_value(r->excl);
96}
97
98static void
99range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bool exclude_end)
100{
101 struct RRange *r = mrb_range_ptr(range);
102
103 range_check(mrb, beg, end);
104 r->excl = exclude_end;
105 if (!r->edges) {
106 r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges));
107 }
108 r->edges->beg = beg;
109 r->edges->end = end;
110}
111/*
112 * call-seq:
113 * Range.new(start, end, exclusive=false) => range
114 *
115 * Constructs a range using the given <i>start</i> and <i>end</i>. If the third
116 * parameter is omitted or is <code>false</code>, the <i>range</i> will include
117 * the end object; otherwise, it will be excluded.
118 */
119
120mrb_value
121mrb_range_initialize(mrb_state *mrb, mrb_value range)
122{
123 mrb_value beg, end;
124 mrb_bool exclusive;
125 int n;
126
127 n = mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive);
128 if (n != 3) {
129 exclusive = FALSE;
130 }
131 /* Ranges are immutable, so that they should be initialized only once. */
132 range_init(mrb, range, beg, end, exclusive);
133 return range;
134}
135/*
136 * call-seq:
137 * range == obj => true or false
138 *
139 * Returns <code>true</code> only if
140 * 1) <i>obj</i> is a Range,
141 * 2) <i>obj</i> has equivalent beginning and end items (by comparing them with <code>==</code>),
142 * 3) <i>obj</i> has the same #exclude_end? setting as <i>rng</t>.
143 *
144 * (0..2) == (0..2) #=> true
145 * (0..2) == Range.new(0,2) #=> true
146 * (0..2) == (0...2) #=> false
147 *
148 */
149
150mrb_value
151mrb_range_eq(mrb_state *mrb, mrb_value range)
152{
153 struct RRange *rr;
154 struct RRange *ro;
155 mrb_value obj;
156
157 mrb_get_args(mrb, "o", &obj);
158
159 if (mrb_obj_equal(mrb, range, obj)) return mrb_true_value();
160 if (!mrb_obj_is_instance_of(mrb, obj, mrb_obj_class(mrb, range))) { /* same class? */
161 return mrb_false_value();
162 }
163
164 rr = mrb_range_ptr(range);
165 ro = mrb_range_ptr(obj);
166 if (!mrb_bool(mrb_funcall(mrb, rr->edges->beg, "==", 1, ro->edges->beg)) ||
167 !mrb_bool(mrb_funcall(mrb, rr->edges->end, "==", 1, ro->edges->end)) ||
168 rr->excl != ro->excl) {
169 return mrb_false_value();
170 }
171 return mrb_true_value();
172}
173
174static mrb_bool
175r_le(mrb_state *mrb, mrb_value a, mrb_value b)
176{
177 mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */
178 /* output :a < b => -1, a = b => 0, a > b => +1 */
179
180 if (mrb_fixnum_p(r)) {
181 mrb_int c = mrb_fixnum(r);
182 if (c == 0 || c == -1) return TRUE;
183 }
184
185 return FALSE;
186}
187
188static mrb_bool
189r_gt(mrb_state *mrb, mrb_value a, mrb_value b)
190{
191 mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b);
192 /* output :a < b => -1, a = b => 0, a > b => +1 */
193
194 return mrb_fixnum_p(r) && mrb_fixnum(r) == 1;
195}
196
197static mrb_bool
198r_ge(mrb_state *mrb, mrb_value a, mrb_value b)
199{
200 mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */
201 /* output :a < b => -1, a = b => 0, a > b => +1 */
202
203 if (mrb_fixnum_p(r)) {
204 mrb_int c = mrb_fixnum(r);
205 if (c == 0 || c == 1) return TRUE;
206 }
207
208 return FALSE;
209}
210
211/*
212 * call-seq:
213 * range === obj => true or false
214 * range.member?(val) => true or false
215 * range.include?(val) => true or false
216 *
217 */
218mrb_value
219mrb_range_include(mrb_state *mrb, mrb_value range)
220{
221 mrb_value val;
222 struct RRange *r = mrb_range_ptr(range);
223 mrb_value beg, end;
224 mrb_bool include_p;
225
226 mrb_get_args(mrb, "o", &val);
227
228 beg = r->edges->beg;
229 end = r->edges->end;
230 include_p = r_le(mrb, beg, val) && /* beg <= val */
231 ((r->excl && r_gt(mrb, end, val)) || /* end > val */
232 (r_ge(mrb, end, val))); /* end >= val */
233
234 return mrb_bool_value(include_p);
235}
236
237static mrb_bool
238range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc)
239{
240 mrb_int beg, end;
241 struct RRange *r = mrb_range_ptr(range);
242
243 if (mrb_type(range) != MRB_TT_RANGE) return FALSE;
244
245 beg = mrb_int(mrb, r->edges->beg);
246 end = mrb_int(mrb, r->edges->end);
247
248 if (beg < 0) {
249 beg += len;
250 if (beg < 0) return FALSE;
251 }
252
253 if (trunc) {
254 if (beg > len) return FALSE;
255 if (end > len) end = len;
256 }
257
258 if (end < 0) end += len;
259 if (!r->excl && (!trunc || end < len))
260 end++; /* include end point */
261 len = end - beg;
262 if (len < 0) len = 0;
263
264 *begp = beg;
265 *lenp = len;
266 return TRUE;
267}
268
269MRB_API mrb_bool
270mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len)
271{
272 return range_beg_len(mrb, range, begp, lenp, len, TRUE);
273}
274
275/* 15.2.14.4.12(x) */
276/*
277 * call-seq:
278 * rng.to_s -> string
279 *
280 * Convert this range object to a printable form.
281 */
282
283static mrb_value
284range_to_s(mrb_state *mrb, mrb_value range)
285{
286 mrb_value str, str2;
287 struct RRange *r = mrb_range_ptr(range);
288
289 str = mrb_obj_as_string(mrb, r->edges->beg);
290 str2 = mrb_obj_as_string(mrb, r->edges->end);
291 str = mrb_str_dup(mrb, str);
292 mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2);
293 mrb_str_cat_str(mrb, str, str2);
294
295 return str;
296}
297
298/* 15.2.14.4.13(x) */
299/*
300 * call-seq:
301 * rng.inspect -> string
302 *
303 * Convert this range object to a printable form (using
304 * <code>inspect</code> to convert the start and end
305 * objects).
306 */
307
308static mrb_value
309range_inspect(mrb_state *mrb, mrb_value range)
310{
311 mrb_value str, str2;
312 struct RRange *r = mrb_range_ptr(range);
313
314 str = mrb_inspect(mrb, r->edges->beg);
315 str2 = mrb_inspect(mrb, r->edges->end);
316 str = mrb_str_dup(mrb, str);
317 mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2);
318 mrb_str_cat_str(mrb, str, str2);
319
320 return str;
321}
322
323/* 15.2.14.4.14(x) */
324/*
325 * call-seq:
326 * rng.eql?(obj) -> true or false
327 *
328 * Returns <code>true</code> only if <i>obj</i> is a Range, has equivalent
329 * beginning and end items (by comparing them with #eql?), and has the same
330 * #exclude_end? setting as <i>rng</i>.
331 *
332 * (0..2).eql?(0..2) #=> true
333 * (0..2).eql?(Range.new(0,2)) #=> true
334 * (0..2).eql?(0...2) #=> false
335 *
336 */
337
338static mrb_value
339range_eql(mrb_state *mrb, mrb_value range)
340{
341 mrb_value obj;
342 struct RRange *r, *o;
343
344 mrb_get_args(mrb, "o", &obj);
345
346 if (mrb_obj_equal(mrb, range, obj)) return mrb_true_value();
347 if (!mrb_obj_is_kind_of(mrb, obj, RANGE_CLASS)) {
348 return mrb_false_value();
349 }
350 if (mrb_type(obj) != MRB_TT_RANGE) return mrb_false_value();
351
352 r = mrb_range_ptr(range);
353 o = mrb_range_ptr(obj);
354 if (!mrb_eql(mrb, r->edges->beg, o->edges->beg) ||
355 !mrb_eql(mrb, r->edges->end, o->edges->end) ||
356 (r->excl != o->excl)) {
357 return mrb_false_value();
358 }
359 return mrb_true_value();
360}
361
362/* 15.2.14.4.15(x) */
363static mrb_value
364range_initialize_copy(mrb_state *mrb, mrb_value copy)
365{
366 mrb_value src;
367 struct RRange *r;
368
369 mrb_get_args(mrb, "o", &src);
370
371 if (mrb_obj_equal(mrb, copy, src)) return copy;
372 if (!mrb_obj_is_instance_of(mrb, src, mrb_obj_class(mrb, copy))) {
373 mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class");
374 }
375
376 r = mrb_range_ptr(src);
377 range_init(mrb, copy, r->edges->beg, r->edges->end, r->excl);
378
379 return copy;
380}
381
382mrb_value
383mrb_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))
384{
385 mrb_int i, j, beg, len;
386 mrb_value result;
387 result = mrb_ary_new(mrb);
388
389 for (i = 0; i < argc; ++i) {
390 if (mrb_fixnum_p(argv[i])) {
391 mrb_ary_push(mrb, result, func(mrb, obj, mrb_fixnum(argv[i])));
392 }
393 else if (range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE)) {
394 mrb_int const end = olen < beg + len ? olen : beg + len;
395 for (j = beg; j < end; ++j) {
396 mrb_ary_push(mrb, result, func(mrb, obj, j));
397 }
398
399 for (; j < beg + len; ++j) {
400 mrb_ary_push(mrb, result, mrb_nil_value());
401 }
402 }
403 else {
404 mrb_raisef(mrb, E_TYPE_ERROR, "invalid values selector: %S", argv[i]);
405 }
406 }
407
408 return result;
409}
410
411void
412mrb_init_range(mrb_state *mrb)
413{
414 struct RClass *r;
415
416 r = mrb_define_class(mrb, "Range", mrb->object_class); /* 15.2.14 */
417 MRB_SET_INSTANCE_TT(r, MRB_TT_RANGE);
418
419 mrb_define_method(mrb, r, "begin", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */
420 mrb_define_method(mrb, r, "end", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */
421 mrb_define_method(mrb, r, "==", mrb_range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */
422 mrb_define_method(mrb, r, "===", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */
423 mrb_define_method(mrb, r, "exclude_end?", mrb_range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */
424 mrb_define_method(mrb, r, "first", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */
425 mrb_define_method(mrb, r, "include?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */
426 mrb_define_method(mrb, r, "initialize", mrb_range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */
427 mrb_define_method(mrb, r, "last", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */
428 mrb_define_method(mrb, r, "member?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */
429
430 mrb_define_method(mrb, r, "to_s", range_to_s, MRB_ARGS_NONE()); /* 15.2.14.4.12(x) */
431 mrb_define_method(mrb, r, "inspect", range_inspect, MRB_ARGS_NONE()); /* 15.2.14.4.13(x) */
432 mrb_define_method(mrb, r, "eql?", range_eql, MRB_ARGS_REQ(1)); /* 15.2.14.4.14(x) */
433 mrb_define_method(mrb, r, "initialize_copy", range_initialize_copy, MRB_ARGS_REQ(1)); /* 15.2.14.4.15(x) */
434}
Note: See TracBrowser for help on using the repository browser.