source: EcnlProtoTool/trunk/mruby-1.3.0/src/range.c@ 331

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

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

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