range.c
DEFINITIONS
This source file includes following functions.
- range_check
- range_failed
- range_init
- rb_range_new
- range_initialize
- range_exclude_end_p
- range_eq
- r_eq
- r_lt
- r_le
- r_gt
- range_eql
- range_hash
- str_step
- step_i
- range_each_func
- range_step
- each_i
- range_each
- range_first
- range_last
- rb_range_beg_len
- range_min
- range_max
- range_to_s
- range_inspect
- member_i
- range_member
- range_include
- Init_Range
1
2
3
4
5
6
7
8
9
10
11
12
13 #include "ruby.h"
14
15 VALUE rb_cRange;
16 static ID id_cmp, id_succ, id_beg, id_end, id_excl;
17
18 #define EXCL(r) RTEST(rb_ivar_get((r), id_excl))
19 #define SET_EXCL(r,v) rb_ivar_set((r), id_excl, (v) ? Qtrue : Qfalse)
20
21 static VALUE
22 range_check(args)
23 VALUE *args;
24 {
25 if (!FIXNUM_P(args[0]) && !rb_obj_is_kind_of(args[0], rb_cNumeric)) {
26 rb_funcall(args[0], id_cmp, 1, args[1]);
27
28 }
29 return Qnil;
30 }
31
32 static VALUE
33 range_failed()
34 {
35 rb_raise(rb_eArgError, "bad value for range");
36 return Qnil;
37 }
38
39 static void
40 range_init(range, beg, end, exclude_end)
41 VALUE range, beg, end;
42 int exclude_end;
43 {
44 VALUE args[2];
45
46 args[0] = beg;
47 args[1] = end;
48
49 if (!FIXNUM_P(beg) || !FIXNUM_P(end)) {
50 rb_rescue(range_check, (VALUE)args, range_failed, 0);
51 }
52
53 SET_EXCL(range, exclude_end);
54 rb_ivar_set(range, id_beg, beg);
55 rb_ivar_set(range, id_end, end);
56 }
57
58 VALUE
59 rb_range_new(beg, end, exclude_end)
60 VALUE beg, end;
61 int exclude_end;
62 {
63 VALUE range = rb_obj_alloc(rb_cRange);
64
65 range_init(range, beg, end, exclude_end);
66 return range;
67 }
68
69 static VALUE
70 range_initialize(argc, argv, range)
71 int argc;
72 VALUE *argv;
73 VALUE range;
74 {
75 VALUE beg, end, flags;
76
77 rb_scan_args(argc, argv, "21", &beg, &end, &flags);
78
79 if (rb_ivar_defined(range, id_beg)) {
80 rb_name_error(rb_intern("initialize"), "`initialize' called twice");
81 }
82 range_init(range, beg, end, RTEST(flags));
83 return Qnil;
84 }
85
86 static VALUE
87 range_exclude_end_p(range)
88 VALUE range;
89 {
90 return EXCL(range) ? Qtrue : Qfalse;
91 }
92
93 static VALUE
94 range_eq(range, obj)
95 VALUE range, obj;
96 {
97 if (range == obj) return Qtrue;
98 if (!rb_obj_is_instance_of(obj, rb_obj_class(range)))
99 return Qfalse;
100
101 if (!rb_equal(rb_ivar_get(range, id_beg), rb_ivar_get(obj, id_beg)))
102 return Qfalse;
103 if (!rb_equal(rb_ivar_get(range, id_end), rb_ivar_get(obj, id_end)))
104 return Qfalse;
105
106 if (EXCL(range) != EXCL(obj)) return Qfalse;
107
108 return Qtrue;
109 }
110
111 static int
112 r_eq(a, b)
113 VALUE a, b;
114 {
115 if (a == b) return Qtrue;
116
117 if (rb_funcall(a, id_cmp, 1, b) == INT2FIX(0))
118 return Qtrue;
119 return Qfalse;
120 }
121
122 static int
123 r_lt(a, b)
124 VALUE a, b;
125 {
126 VALUE r = rb_funcall(a, id_cmp, 1, b);
127
128 if (rb_cmpint(r) < 0) return Qtrue;
129 return Qfalse;
130 }
131
132 static int
133 r_le(a, b)
134 VALUE a, b;
135 {
136 VALUE r = rb_funcall(a, id_cmp, 1, b);
137
138 if (rb_cmpint(r) <= 0) return Qtrue;
139 return Qfalse;
140 }
141
142 static int
143 r_gt(a,b)
144 VALUE a, b;
145 {
146 VALUE r = rb_funcall(a, id_cmp, 1, b);
147
148 if (rb_cmpint(r) > 0) return Qtrue;
149 return Qfalse;
150 }
151
152 static VALUE
153 range_eql(range, obj)
154 VALUE range, obj;
155 {
156 if (range == obj) return Qtrue;
157 if (!rb_obj_is_instance_of(obj, rb_obj_class(range)))
158 return Qfalse;
159
160 if (!rb_eql(rb_ivar_get(range, id_beg), rb_ivar_get(obj, id_beg)))
161 return Qfalse;
162 if (!rb_eql(rb_ivar_get(range, id_end), rb_ivar_get(obj, id_end)))
163 return Qfalse;
164
165 if (EXCL(range) != EXCL(obj)) return Qfalse;
166
167 return Qtrue;
168 }
169
170 static VALUE
171 range_hash(range)
172 VALUE range;
173 {
174 long hash = EXCL(range);
175 VALUE v;
176
177 v = rb_hash(rb_ivar_get(range, id_beg));
178 hash ^= v << 1;
179 v = rb_hash(rb_ivar_get(range, id_end));
180 hash ^= v << 9;
181 hash ^= EXCL(range) << 24;
182
183 return LONG2FIX(hash);
184 }
185
186 static VALUE
187 str_step(args)
188 VALUE *args;
189 {
190 return rb_str_upto(args[0], args[1], EXCL(args[2]));
191 }
192
193 static VALUE
194 step_i(i, iter)
195 VALUE i;
196 long *iter;
197 {
198 iter[0]--;
199 if (iter[0] == 0) {
200 rb_yield(i);
201 iter[0] = iter[1];
202 }
203 return Qnil;
204 }
205
206 static void
207 range_each_func(range, func, v, e, arg)
208 VALUE range;
209 void (*func) _((VALUE, void*));
210 VALUE v, e;
211 void *arg;
212 {
213 if (EXCL(range)) {
214 while (r_lt(v, e)) {
215 (*func)(v, arg);
216 v = rb_funcall(v, id_succ, 0, 0);
217 }
218 }
219 else {
220 while (r_le(v, e)) {
221 (*func)(v, arg);
222 v = rb_funcall(v, id_succ, 0, 0);
223 }
224 }
225 }
226
227 static VALUE
228 range_step(argc, argv, range)
229 int argc;
230 VALUE *argv;
231 VALUE range;
232 {
233 VALUE b, e, step;
234 long unit;
235
236 b = rb_ivar_get(range, id_beg);
237 e = rb_ivar_get(range, id_end);
238 if (rb_scan_args(argc, argv, "01", &step) == 0) {
239 step = INT2FIX(1);
240 }
241
242 unit = NUM2LONG(step);
243 if (unit <= 0) {
244 rb_raise(rb_eArgError, "step can't be <= 0");
245 }
246 if (FIXNUM_P(b) && FIXNUM_P(e)) {
247 long end = FIX2LONG(e);
248 long i;
249
250 if (!EXCL(range)) end += 1;
251 for (i=FIX2LONG(b); i<end; i+=unit) {
252 rb_yield(LONG2NUM(i));
253 }
254 }
255 else if (rb_obj_is_kind_of(b, rb_cNumeric)) {
256 ID c = rb_intern(EXCL(range) ? "<" : "<=");
257
258 while (RTEST(rb_funcall(b, c, 1, e))) {
259 rb_yield(b);
260 b = rb_funcall(b, '+', 1, step);
261 }
262 }
263 else if (TYPE(b) == T_STRING) {
264 VALUE args[5];
265 long iter[2];
266
267 args[0] = b; args[1] = e; args[2] = range;
268 iter[0] = 1; iter[1] = unit;
269 rb_iterate((VALUE(*)_((VALUE)))str_step, (VALUE)args, step_i, (VALUE)iter);
270 }
271 else {
272 long args[2];
273
274 if (!rb_respond_to(b, id_succ)) {
275 rb_raise(rb_eTypeError, "cannot iterate from %s",
276 rb_class2name(CLASS_OF(b)));
277 }
278
279 args[0] = 1;
280 args[1] = unit;
281 range_each_func(range, step_i, b, e, args);
282 }
283 return range;
284 }
285
286 static void
287 each_i(v, arg)
288 VALUE v;
289 void *arg;
290 {
291 rb_yield(v);
292 }
293
294 static VALUE
295 range_each(range)
296 VALUE range;
297 {
298 VALUE beg, end;
299
300 beg = rb_ivar_get(range, id_beg);
301 end = rb_ivar_get(range, id_end);
302
303 if (!rb_respond_to(beg, id_succ)) {
304 rb_raise(rb_eTypeError, "cannot iterate from %s",
305 rb_class2name(CLASS_OF(beg)));
306 }
307 if (TYPE(beg) == T_STRING) {
308 VALUE args[5];
309 long iter[2];
310
311 args[0] = beg; args[1] = end; args[2] = range;
312 iter[0] = 1; iter[1] = 1;
313 rb_iterate((VALUE(*)_((VALUE)))str_step, (VALUE)args, step_i, (VALUE)iter);
314 }
315 else {
316 range_each_func(range, each_i, beg, end, 0);
317 }
318 return range;
319 }
320
321 static VALUE
322 range_first(range)
323 VALUE range;
324 {
325 return rb_ivar_get(range, id_beg);
326 }
327
328 static VALUE
329 range_last(range)
330 VALUE range;
331 {
332 return rb_ivar_get(range, id_end);
333 }
334
335 VALUE
336 rb_range_beg_len(range, begp, lenp, len, err)
337 VALUE range;
338 long *begp, *lenp;
339 long len;
340 int err;
341 {
342 long beg, end, b, e;
343
344 if (!rb_obj_is_kind_of(range, rb_cRange)) return Qfalse;
345
346 beg = b = NUM2LONG(rb_ivar_get(range, id_beg));
347 end = e = NUM2LONG(rb_ivar_get(range, id_end));
348
349 if (beg < 0) {
350 beg += len;
351 if (beg < 0) goto out_of_range;
352 }
353 if (err == 0 || err == 2) {
354 if (beg > len) goto out_of_range;
355 if (end > len || (!EXCL(range) && end == len))
356 end = len;
357 }
358 if (end < 0) {
359 end += len;
360 if (end < 0) {
361 if (beg == 0 && end == -1 && !EXCL(range)) {
362 len = 0;
363 goto length_set;
364 }
365 goto out_of_range;
366 }
367 }
368 len = end - beg;
369 if (!EXCL(range)) len++;
370 if (len < 0) goto out_of_range;
371
372 length_set:
373 *begp = beg;
374 *lenp = len;
375
376 return Qtrue;
377
378 out_of_range:
379 if (err) {
380 rb_raise(rb_eRangeError, "%ld..%s%ld out of range",
381 b, EXCL(range)? "." : "", e);
382 }
383 return Qnil;
384 }
385
386 static VALUE
387 range_min(range)
388 VALUE range;
389
390 {
391 VALUE b = rb_ivar_get(range, id_beg);
392 VALUE e = rb_ivar_get(range, id_end);
393
394 if (r_le(b, e)) return b;
395 return e;
396 }
397
398 static VALUE
399 range_max(range)
400 VALUE range;
401 {
402 VALUE b = rb_ivar_get(range, id_beg);
403 VALUE e = rb_ivar_get(range, id_end);
404
405 if (r_gt(b, e)) return b;
406 return e;
407 }
408
409 static VALUE
410 range_to_s(range)
411 VALUE range;
412 {
413 VALUE str, str2;
414
415 str = rb_obj_as_string(rb_ivar_get(range, id_beg));
416 str2 = rb_obj_as_string(rb_ivar_get(range, id_end));
417 str = rb_str_dup(str);
418 rb_str_cat(str, "...", EXCL(range)?3:2);
419 rb_str_append(str, str2);
420 OBJ_INFECT(str, str2);
421
422 return str;
423 }
424
425 static VALUE
426 range_inspect(range)
427 VALUE range;
428 {
429 VALUE str, str2;
430
431 str = rb_inspect(rb_ivar_get(range, id_beg));
432 str2 = rb_inspect(rb_ivar_get(range, id_end));
433 str = rb_str_dup(str);
434 rb_str_cat(str, "...", EXCL(range)?3:2);
435 rb_str_append(str, str2);
436 OBJ_INFECT(str, str2);
437
438 return str;
439 }
440
441 static void
442 member_i(v, args)
443 VALUE v;
444 VALUE *args;
445 {
446 if (rb_equal(v, args[0])) {
447 args[1] = Qtrue;
448 }
449 }
450
451 static VALUE
452 range_member(range, val)
453 VALUE range, val;
454 {
455 VALUE beg, end;
456 VALUE args[2];
457
458 beg = rb_ivar_get(range, id_beg);
459 end = rb_ivar_get(range, id_end);
460
461 if (!rb_respond_to(beg, id_succ)) {
462 rb_raise(rb_eTypeError, "cannot iterate from %s",
463 rb_class2name(CLASS_OF(beg)));
464 }
465 args[0] = val;
466 args[1] = Qfalse;
467 range_each_func(range, member_i, beg, end, args);
468 return args[1];
469 }
470
471 static VALUE
472 range_include(range, val)
473 VALUE range, val;
474 {
475 VALUE beg, end;
476
477 beg = rb_ivar_get(range, id_beg);
478 end = rb_ivar_get(range, id_end);
479 if (r_gt(beg, val)) return Qfalse;
480 if (EXCL(range)) {
481 if (r_lt(val, end)) return Qtrue;
482 }
483 else {
484 if (r_le(val, end)) return Qtrue;
485 }
486 return Qfalse;
487 }
488
489 void
490 Init_Range()
491 {
492 rb_cRange = rb_define_class("Range", rb_cObject);
493 rb_include_module(rb_cRange, rb_mEnumerable);
494 rb_define_method(rb_cRange, "initialize", range_initialize, -1);
495 rb_define_method(rb_cRange, "==", range_eq, 1);
496 rb_define_method(rb_cRange, "===", range_include, 1);
497 rb_define_method(rb_cRange, "eql?", range_eql, 1);
498 rb_define_method(rb_cRange, "hash", range_hash, 0);
499 rb_define_method(rb_cRange, "each", range_each, 0);
500 rb_define_method(rb_cRange, "step", range_step, -1);
501 rb_define_method(rb_cRange, "first", range_first, 0);
502 rb_define_method(rb_cRange, "last", range_last, 0);
503 rb_define_method(rb_cRange, "begin", range_first, 0);
504 rb_define_method(rb_cRange, "end", range_last, 0);
505 rb_define_method(rb_cRange, "min", range_min, 0);
506 rb_define_method(rb_cRange, "max", range_max, 0);
507 rb_define_method(rb_cRange, "to_s", range_to_s, 0);
508 rb_define_method(rb_cRange, "inspect", range_inspect, 0);
509 rb_define_alias(rb_cRange, "to_ary", "to_a");
510
511 rb_define_method(rb_cRange, "exclude_end?", range_exclude_end_p, 0);
512
513 rb_define_method(rb_cRange, "member?", range_member, 1);
514 rb_define_method(rb_cRange, "include?", range_include, 1);
515
516 id_cmp = rb_intern("<=>");
517 id_succ = rb_intern("succ");
518 id_beg = rb_intern("begin");
519 id_end = rb_intern("end");
520 id_excl = rb_intern("excl");
521 }