Ruby
1.9.3p448(2013-06-27revision41675)
Main Page
Modules
Data Structures
Files
File List
Globals
range.c
Go to the documentation of this file.
1
/**********************************************************************
2
3
range.c -
4
5
$Author: tarui $
6
created at: Thu Aug 19 17:46:47 JST 1993
7
8
Copyright (C) 1993-2007 Yukihiro Matsumoto
9
10
**********************************************************************/
11
12
#include "
ruby/ruby.h
"
13
#include "
ruby/encoding.h
"
14
#include "
internal.h
"
15
16
VALUE
rb_cRange
;
17
static
ID
id_cmp
,
id_succ
,
id_beg
,
id_end
,
id_excl
;
18
19
#define RANGE_BEG(r) (RSTRUCT(r)->as.ary[0])
20
#define RANGE_END(r) (RSTRUCT(r)->as.ary[1])
21
#define RANGE_EXCL(r) (RSTRUCT(r)->as.ary[2])
22
23
#define EXCL(r) RTEST(RANGE_EXCL(r))
24
#define SET_EXCL(r,v) (RSTRUCT(r)->as.ary[2] = (v) ? Qtrue : Qfalse)
25
26
static
VALUE
27
range_failed
(
void
)
28
{
29
rb_raise
(
rb_eArgError
,
"bad value for range"
);
30
return
Qnil
;
/* dummy */
31
}
32
33
static
VALUE
34
range_check
(
VALUE
*
args
)
35
{
36
return
rb_funcall
(args[0],
id_cmp
, 1, args[1]);
37
}
38
39
static
void
40
range_init
(
VALUE
range
,
VALUE
beg,
VALUE
end,
int
exclude_end)
41
{
42
VALUE
args
[2];
43
44
args[0] = beg;
45
args[1] = end;
46
47
if
(!
FIXNUM_P
(beg) || !
FIXNUM_P
(end)) {
48
VALUE
v
;
49
50
v =
rb_rescue
(
range_check
, (
VALUE
)args,
range_failed
, 0);
51
if
(
NIL_P
(v))
52
range_failed
();
53
}
54
55
SET_EXCL
(range, exclude_end);
56
RSTRUCT
(range)->as.ary[0] = beg;
57
RSTRUCT
(range)->as.ary[1] = end;
58
}
59
60
VALUE
61
rb_range_new
(
VALUE
beg,
VALUE
end,
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
/*
70
* call-seq:
71
* Range.new(start, end, exclusive=false) -> range
72
*
73
* Constructs a range using the given <i>start</i> and <i>end</i>. If the third
74
* parameter is omitted or is <code>false</code>, the <i>range</i> will include
75
* the end object; otherwise, it will be excluded.
76
*/
77
78
static
VALUE
79
range_initialize
(
int
argc
,
VALUE
*
argv
,
VALUE
range
)
80
{
81
VALUE
beg, end, flags;
82
83
rb_scan_args
(argc, argv,
"21"
, &beg, &end, &flags);
84
/* Ranges are immutable, so that they should be initialized only once. */
85
if
(
RANGE_EXCL
(range) !=
Qnil
) {
86
rb_name_error
(
rb_intern
(
"initialize"
),
"`initialize' called twice"
);
87
}
88
range_init
(range, beg, end,
RTEST
(flags));
89
return
Qnil
;
90
}
91
92
#define range_initialize_copy rb_struct_init_copy
/* :nodoc: */
93
94
/*
95
* call-seq:
96
* rng.exclude_end? -> true or false
97
*
98
* Returns <code>true</code> if <i>rng</i> excludes its end value.
99
*/
100
101
static
VALUE
102
range_exclude_end_p
(
VALUE
range
)
103
{
104
return
EXCL
(range) ?
Qtrue
:
Qfalse
;
105
}
106
107
static
VALUE
108
recursive_equal
(
VALUE
range
,
VALUE
obj,
int
recur
)
109
{
110
if
(recur)
return
Qtrue
;
/* Subtle! */
111
if
(!
rb_equal
(
RANGE_BEG
(range),
RANGE_BEG
(obj)))
112
return
Qfalse
;
113
if
(!
rb_equal
(
RANGE_END
(range),
RANGE_END
(obj)))
114
return
Qfalse
;
115
116
if
(
EXCL
(range) !=
EXCL
(obj))
117
return
Qfalse
;
118
return
Qtrue
;
119
}
120
121
122
/*
123
* call-seq:
124
* rng == obj -> true or false
125
*
126
* Returns <code>true</code> only if <i>obj</i> is a Range, has equivalent
127
* beginning and end items (by comparing them with <code>==</code>), and has
128
* the same <code>exclude_end?</code> setting as <i>rng</i>.
129
*
130
* (0..2) == (0..2) #=> true
131
* (0..2) == Range.new(0,2) #=> true
132
* (0..2) == (0...2) #=> false
133
*
134
*/
135
136
static
VALUE
137
range_eq
(
VALUE
range
,
VALUE
obj)
138
{
139
if
(range == obj)
140
return
Qtrue
;
141
if
(!
rb_obj_is_kind_of
(obj,
rb_cRange
))
142
return
Qfalse
;
143
144
return
rb_exec_recursive_paired
(
recursive_equal
, range, obj, obj);
145
}
146
147
static
int
148
r_lt
(
VALUE
a,
VALUE
b)
149
{
150
VALUE
r =
rb_funcall
(a,
id_cmp
, 1, b);
151
152
if
(
NIL_P
(r))
153
return
(
int
)
Qfalse
;
154
if
(
rb_cmpint
(r, a, b) < 0)
155
return
(
int
)
Qtrue
;
156
return
(
int
)
Qfalse
;
157
}
158
159
static
int
160
r_le
(
VALUE
a,
VALUE
b)
161
{
162
int
c;
163
VALUE
r =
rb_funcall
(a,
id_cmp
, 1, b);
164
165
if
(
NIL_P
(r))
166
return
(
int
)
Qfalse
;
167
c =
rb_cmpint
(r, a, b);
168
if
(c == 0)
169
return
(
int
)
INT2FIX
(0);
170
if
(c < 0)
171
return
(
int
)
Qtrue
;
172
return
(
int
)
Qfalse
;
173
}
174
175
176
static
VALUE
177
recursive_eql
(
VALUE
range
,
VALUE
obj,
int
recur
)
178
{
179
if
(recur)
return
Qtrue
;
/* Subtle! */
180
if
(!
rb_eql
(
RANGE_BEG
(range),
RANGE_BEG
(obj)))
181
return
Qfalse
;
182
if
(!
rb_eql
(
RANGE_END
(range),
RANGE_END
(obj)))
183
return
Qfalse
;
184
185
if
(
EXCL
(range) !=
EXCL
(obj))
186
return
Qfalse
;
187
return
Qtrue
;
188
}
189
190
/*
191
* call-seq:
192
* rng.eql?(obj) -> true or false
193
*
194
* Returns <code>true</code> only if <i>obj</i> is a Range, has equivalent
195
* beginning and end items (by comparing them with #eql?), and has the same
196
* #exclude_end? setting as <i>rng</i>.
197
*
198
* (0..2).eql?(0..2) #=> true
199
* (0..2).eql?(Range.new(0,2)) #=> true
200
* (0..2).eql?(0...2) #=> false
201
*
202
*/
203
204
static
VALUE
205
range_eql
(
VALUE
range
,
VALUE
obj)
206
{
207
if
(range == obj)
208
return
Qtrue
;
209
if
(!
rb_obj_is_kind_of
(obj,
rb_cRange
))
210
return
Qfalse
;
211
return
rb_exec_recursive_paired
(
recursive_eql
, range, obj, obj);
212
}
213
214
static
VALUE
215
recursive_hash
(
VALUE
range
,
VALUE
dummy,
int
recur
)
216
{
217
st_index_t
hash
=
EXCL
(range);
218
VALUE
v
;
219
220
hash =
rb_hash_start
(hash);
221
if
(!recur) {
222
v =
rb_hash
(
RANGE_BEG
(range));
223
hash =
rb_hash_uint
(hash,
NUM2LONG
(v));
224
v =
rb_hash
(
RANGE_END
(range));
225
hash =
rb_hash_uint
(hash,
NUM2LONG
(v));
226
}
227
hash =
rb_hash_uint
(hash,
EXCL
(range) << 24);
228
hash =
rb_hash_end
(hash);
229
230
return
LONG2FIX
(hash);
231
}
232
233
/*
234
* call-seq:
235
* rng.hash -> fixnum
236
*
237
* Generate a hash value such that two ranges with the same start and
238
* end points, and the same value for the "exclude end" flag, generate
239
* the same hash value.
240
*/
241
242
static
VALUE
243
range_hash
(
VALUE
range
)
244
{
245
return
rb_exec_recursive_outer
(
recursive_hash
, range, 0);
246
}
247
248
static
void
249
range_each_func
(
VALUE
range
,
VALUE
(*
func
) (
VALUE
,
void
*),
void
*
arg
)
250
{
251
int
c;
252
VALUE
b =
RANGE_BEG
(range);
253
VALUE
e =
RANGE_END
(range);
254
VALUE
v
= b;
255
256
if
(
EXCL
(range)) {
257
while
(
r_lt
(v, e)) {
258
(*func) (
v
,
arg
);
259
v =
rb_funcall
(v,
id_succ
, 0, 0);
260
}
261
}
262
else
{
263
while
((c =
r_le
(v, e)) !=
Qfalse
) {
264
(*func) (
v
,
arg
);
265
if
(c == (
int
)
INT2FIX
(0))
266
break
;
267
v =
rb_funcall
(v,
id_succ
, 0, 0);
268
}
269
}
270
}
271
272
static
VALUE
273
sym_step_i
(
VALUE
i
,
void
*
arg
)
274
{
275
VALUE
*iter =
arg
;
276
277
if
(
FIXNUM_P
(iter[0])) {
278
iter[0] -=
INT2FIX
(1) & ~
FIXNUM_FLAG
;
279
}
280
else
{
281
iter[0] =
rb_funcall
(iter[0],
'-'
, 1,
INT2FIX
(1));
282
}
283
if
(iter[0] ==
INT2FIX
(0)) {
284
rb_yield
(
rb_str_intern
(i));
285
iter[0] = iter[1];
286
}
287
return
Qnil
;
288
}
289
290
static
VALUE
291
step_i
(
VALUE
i
,
void
*
arg
)
292
{
293
VALUE
*iter =
arg
;
294
295
if
(
FIXNUM_P
(iter[0])) {
296
iter[0] -=
INT2FIX
(1) & ~
FIXNUM_FLAG
;
297
}
298
else
{
299
iter[0] =
rb_funcall
(iter[0],
'-'
, 1,
INT2FIX
(1));
300
}
301
if
(iter[0] ==
INT2FIX
(0)) {
302
rb_yield
(i);
303
iter[0] = iter[1];
304
}
305
return
Qnil
;
306
}
307
308
static
int
309
discrete_object_p
(
VALUE
obj)
310
{
311
if
(
rb_obj_is_kind_of
(obj,
rb_cTime
))
return
FALSE
;
/* until Time#succ removed */
312
return
rb_respond_to
(obj,
id_succ
);
313
}
314
315
316
/*
317
* call-seq:
318
* rng.step(n=1) {| obj | block } -> rng
319
* rng.step(n=1) -> an_enumerator
320
*
321
* Iterates over <i>rng</i>, passing each <i>n</i>th element to the block. If
322
* the range contains numbers, <i>n</i> is added for each iteration. Otherwise
323
* <code>step</code> invokes <code>succ</code> to iterate through range
324
* elements. The following code uses class <code>Xs</code>, which is defined
325
* in the class-level documentation.
326
*
327
* If no block is given, an enumerator is returned instead.
328
*
329
* range = Xs.new(1)..Xs.new(10)
330
* range.step(2) {|x| puts x}
331
* range.step(3) {|x| puts x}
332
*
333
* <em>produces:</em>
334
*
335
* 1 x
336
* 3 xxx
337
* 5 xxxxx
338
* 7 xxxxxxx
339
* 9 xxxxxxxxx
340
* 1 x
341
* 4 xxxx
342
* 7 xxxxxxx
343
* 10 xxxxxxxxxx
344
*/
345
346
347
static
VALUE
348
range_step
(
int
argc
,
VALUE
*
argv
,
VALUE
range)
349
{
350
VALUE
b, e, step, tmp;
351
352
RETURN_ENUMERATOR
(range, argc, argv);
353
354
b =
RANGE_BEG
(range);
355
e =
RANGE_END
(range);
356
if
(argc == 0) {
357
step =
INT2FIX
(1);
358
}
359
else
{
360
rb_scan_args
(argc, argv,
"01"
, &step);
361
if
(!
rb_obj_is_kind_of
(step,
rb_cNumeric
)) {
362
step =
rb_to_int
(step);
363
}
364
if
(
rb_funcall
(step,
'<'
, 1,
INT2FIX
(0))) {
365
rb_raise
(
rb_eArgError
,
"step can't be negative"
);
366
}
367
else
if
(!
rb_funcall
(step,
'>'
, 1,
INT2FIX
(0))) {
368
rb_raise
(
rb_eArgError
,
"step can't be 0"
);
369
}
370
}
371
372
if
(
FIXNUM_P
(b) &&
FIXNUM_P
(e) &&
FIXNUM_P
(step)) {
/* fixnums are special */
373
long
end =
FIX2LONG
(e);
374
long
i
, unit =
FIX2LONG
(step);
375
376
if
(!
EXCL
(range))
377
end += 1;
378
i =
FIX2LONG
(b);
379
while
(i < end) {
380
rb_yield
(
LONG2NUM
(i));
381
if
(i + unit < i)
break
;
382
i += unit;
383
}
384
385
}
386
else
if
(
SYMBOL_P
(b) &&
SYMBOL_P
(e)) {
/* symbols are special */
387
VALUE
args
[2], iter[2];
388
389
args[0] =
rb_sym_to_s
(e);
390
args[1] =
EXCL
(range) ?
Qtrue
:
Qfalse
;
391
iter[0] =
INT2FIX
(1);
392
iter[1] = step;
393
rb_block_call
(
rb_sym_to_s
(b),
rb_intern
(
"upto"
), 2, args,
sym_step_i
, (
VALUE
)iter);
394
}
395
else
if
(
ruby_float_step
(b, e, step,
EXCL
(range))) {
396
/* done */
397
}
398
else
if
(
rb_obj_is_kind_of
(b,
rb_cNumeric
) ||
399
!
NIL_P
(
rb_check_to_integer
(b,
"to_int"
)) ||
400
!
NIL_P
(
rb_check_to_integer
(e,
"to_int"
))) {
401
ID
op =
EXCL
(range) ?
'<'
:
rb_intern
(
"<="
);
402
VALUE
v
= b;
403
int
i
= 0;
404
405
while
(
RTEST
(
rb_funcall
(v, op, 1, e))) {
406
rb_yield
(v);
407
i++;
408
v =
rb_funcall
(b,
'+'
, 1,
rb_funcall
(
INT2NUM
(i),
'*'
, 1, step));
409
}
410
}
411
else
{
412
tmp =
rb_check_string_type
(b);
413
414
if
(!
NIL_P
(tmp)) {
415
VALUE
args
[2], iter[2];
416
417
b = tmp;
418
args[0] = e;
419
args[1] =
EXCL
(range) ?
Qtrue
:
Qfalse
;
420
iter[0] =
INT2FIX
(1);
421
iter[1] = step;
422
rb_block_call
(b,
rb_intern
(
"upto"
), 2, args,
step_i
, (
VALUE
)iter);
423
}
424
else
{
425
VALUE
args
[2];
426
427
if
(!
discrete_object_p
(b)) {
428
rb_raise
(
rb_eTypeError
,
"can't iterate from %s"
,
429
rb_obj_classname
(b));
430
}
431
args[0] =
INT2FIX
(1);
432
args[1] = step;
433
range_each_func
(range,
step_i
, args);
434
}
435
}
436
return
range
;
437
}
438
439
static
VALUE
440
each_i
(
VALUE
v
,
void
*
arg
)
441
{
442
rb_yield
(v);
443
return
Qnil
;
444
}
445
446
static
VALUE
447
sym_each_i
(
VALUE
v
,
void
*
arg
)
448
{
449
rb_yield
(
rb_str_intern
(v));
450
return
Qnil
;
451
}
452
453
/*
454
* call-seq:
455
* rng.each {| i | block } -> rng
456
* rng.each -> an_enumerator
457
*
458
* Iterates over the elements <i>rng</i>, passing each in turn to the
459
* block. You can only iterate if the start object of the range
460
* supports the +succ+ method (which means that you can't iterate over
461
* ranges of +Float+ objects).
462
*
463
* If no block is given, an enumerator is returned instead.
464
*
465
* (10..15).each do |n|
466
* print n, ' '
467
* end
468
*
469
* <em>produces:</em>
470
*
471
* 10 11 12 13 14 15
472
*/
473
474
static
VALUE
475
range_each
(
VALUE
range)
476
{
477
VALUE
beg, end;
478
479
RETURN_ENUMERATOR
(range, 0, 0);
480
481
beg =
RANGE_BEG
(range);
482
end =
RANGE_END
(range);
483
484
if
(
FIXNUM_P
(beg) &&
FIXNUM_P
(end)) {
/* fixnums are special */
485
long
lim =
FIX2LONG
(end);
486
long
i
;
487
488
if
(!
EXCL
(range))
489
lim += 1;
490
for
(i =
FIX2LONG
(beg); i < lim; i++) {
491
rb_yield
(
LONG2FIX
(i));
492
}
493
}
494
else
if
(
SYMBOL_P
(beg) &&
SYMBOL_P
(end)) {
/* symbols are special */
495
VALUE
args
[2];
496
497
args[0] =
rb_sym_to_s
(end);
498
args[1] =
EXCL
(range) ?
Qtrue
:
Qfalse
;
499
rb_block_call
(
rb_sym_to_s
(beg),
rb_intern
(
"upto"
), 2, args,
sym_each_i
, 0);
500
}
501
else
{
502
VALUE
tmp =
rb_check_string_type
(beg);
503
504
if
(!
NIL_P
(tmp)) {
505
VALUE
args
[2];
506
507
args[0] = end;
508
args[1] =
EXCL
(range) ?
Qtrue
:
Qfalse
;
509
rb_block_call
(tmp,
rb_intern
(
"upto"
), 2, args,
rb_yield
, 0);
510
}
511
else
{
512
if
(!
discrete_object_p
(beg)) {
513
rb_raise
(
rb_eTypeError
,
"can't iterate from %s"
,
514
rb_obj_classname
(beg));
515
}
516
range_each_func
(range,
each_i
,
NULL
);
517
}
518
}
519
return
range
;
520
}
521
522
/*
523
* call-seq:
524
* rng.begin -> obj
525
*
526
* Returns the first object in <i>rng</i>.
527
*/
528
529
static
VALUE
530
range_begin
(
VALUE
range)
531
{
532
return
RANGE_BEG
(range);
533
}
534
535
536
/*
537
* call-seq:
538
* rng.end -> obj
539
*
540
* Returns the object that defines the end of <i>rng</i>.
541
*
542
* (1..10).end #=> 10
543
* (1...10).end #=> 10
544
*/
545
546
547
static
VALUE
548
range_end
(
VALUE
range)
549
{
550
return
RANGE_END
(range);
551
}
552
553
554
static
VALUE
555
first_i
(
VALUE
i
,
VALUE
*ary)
556
{
557
long
n =
NUM2LONG
(ary[0]);
558
559
if
(n <= 0) {
560
rb_iter_break
();
561
}
562
rb_ary_push
(ary[1], i);
563
n--;
564
ary[0] =
INT2NUM
(n);
565
return
Qnil
;
566
}
567
568
/*
569
* call-seq:
570
* rng.first -> obj
571
* rng.first(n) -> an_array
572
*
573
* Returns the first object in <i>rng</i>, or the first +n+ elements.
574
*/
575
576
static
VALUE
577
range_first
(
int
argc
,
VALUE
*
argv
,
VALUE
range)
578
{
579
VALUE
n, ary[2];
580
581
if
(argc == 0)
return
RANGE_BEG
(range);
582
583
rb_scan_args
(argc, argv,
"1"
, &n);
584
ary[0] = n;
585
ary[1] =
rb_ary_new2
(
NUM2LONG
(n));
586
rb_block_call
(range,
rb_intern
(
"each"
), 0, 0,
first_i
, (
VALUE
)ary);
587
588
return
ary[1];
589
}
590
591
592
/*
593
* call-seq:
594
* rng.last -> obj
595
* rng.last(n) -> an_array
596
*
597
* Returns the last object in <i>rng</i>, or the last +n+ elements.
598
*/
599
600
static
VALUE
601
range_last
(
int
argc
,
VALUE
*
argv
,
VALUE
range)
602
{
603
if
(argc == 0)
return
RANGE_END
(range);
604
return
rb_ary_last
(argc, argv,
rb_Array
(range));
605
}
606
607
608
/*
609
* call-seq:
610
* rng.min -> obj
611
* rng.min {| a,b | block } -> obj
612
*
613
* Returns the minimum value in <i>rng</i>. The second uses
614
* the block to compare values. Returns nil if the first
615
* value in range is larger than the last value.
616
*
617
*/
618
619
620
static
VALUE
621
range_min
(
VALUE
range)
622
{
623
if
(
rb_block_given_p
()) {
624
return
rb_call_super
(0, 0);
625
}
626
else
{
627
VALUE
b =
RANGE_BEG
(range);
628
VALUE
e =
RANGE_END
(range);
629
int
c =
rb_cmpint
(
rb_funcall
(b,
id_cmp
, 1, e), b, e);
630
631
if
(c > 0 || (c == 0 &&
EXCL
(range)))
632
return
Qnil
;
633
return
b;
634
}
635
}
636
637
/*
638
* call-seq:
639
* rng.max -> obj
640
* rng.max {| a,b | block } -> obj
641
*
642
* Returns the maximum value in <i>rng</i>. The second uses
643
* the block to compare values. Returns nil if the first
644
* value in range is larger than the last value.
645
*
646
*/
647
648
static
VALUE
649
range_max
(
VALUE
range)
650
{
651
VALUE
e =
RANGE_END
(range);
652
int
nm =
FIXNUM_P
(e) ||
rb_obj_is_kind_of
(e,
rb_cNumeric
);
653
654
if
(
rb_block_given_p
() || (
EXCL
(range) && !nm)) {
655
return
rb_call_super
(0, 0);
656
}
657
else
{
658
VALUE
b =
RANGE_BEG
(range);
659
int
c =
rb_cmpint
(
rb_funcall
(b,
id_cmp
, 1, e), b, e);
660
661
if
(c > 0)
662
return
Qnil
;
663
if
(
EXCL
(range)) {
664
if
(!
FIXNUM_P
(e) && !
rb_obj_is_kind_of
(e,
rb_cInteger
)) {
665
rb_raise
(
rb_eTypeError
,
"cannot exclude non Integer end value"
);
666
}
667
if
(c == 0)
return
Qnil
;
668
if
(!
FIXNUM_P
(b) && !
rb_obj_is_kind_of
(b,
rb_cInteger
)) {
669
rb_raise
(
rb_eTypeError
,
"cannot exclude end value with non Integer begin value"
);
670
}
671
if
(
FIXNUM_P
(e)) {
672
return
LONG2NUM
(
FIX2LONG
(e) - 1);
673
}
674
return
rb_funcall
(e,
'-'
, 1,
INT2FIX
(1));
675
}
676
return
e;
677
}
678
}
679
680
int
681
rb_range_values
(
VALUE
range,
VALUE
*begp,
VALUE
*endp,
int
*exclp)
682
{
683
VALUE
b, e;
684
int
excl;
685
686
if
(
rb_obj_is_kind_of
(range,
rb_cRange
)) {
687
b =
RANGE_BEG
(range);
688
e =
RANGE_END
(range);
689
excl =
EXCL
(range);
690
}
691
else
{
692
if
(!
rb_respond_to
(range,
id_beg
))
return
(
int
)
Qfalse
;
693
if
(!
rb_respond_to
(range,
id_end
))
return
(
int
)
Qfalse
;
694
b =
rb_funcall
(range,
id_beg
, 0);
695
e =
rb_funcall
(range,
id_end
, 0);
696
excl =
RTEST
(
rb_funcall
(range,
rb_intern
(
"exclude_end?"
), 0));
697
}
698
*begp = b;
699
*endp = e;
700
*exclp = excl;
701
return
(
int
)
Qtrue
;
702
}
703
704
VALUE
705
rb_range_beg_len
(
VALUE
range,
long
*begp,
long
*lenp,
long
len
,
int
err
)
706
{
707
long
beg, end, origbeg, origend;
708
VALUE
b, e;
709
int
excl;
710
711
if
(!
rb_range_values
(range, &b, &e, &excl))
712
return
Qfalse
;
713
beg =
NUM2LONG
(b);
714
end =
NUM2LONG
(e);
715
origbeg = beg;
716
origend = end;
717
if
(beg < 0) {
718
beg +=
len
;
719
if
(beg < 0)
720
goto
out_of_range;
721
}
722
if
(err == 0 || err == 2) {
723
if
(beg > len)
724
goto
out_of_range;
725
if
(end > len)
726
end =
len
;
727
}
728
if
(end < 0)
729
end +=
len
;
730
if
(!excl)
731
end++;
/* include end point */
732
len = end - beg;
733
if
(len < 0)
734
len = 0;
735
736
*begp = beg;
737
*lenp =
len
;
738
return
Qtrue
;
739
740
out_of_range:
741
if
(err) {
742
rb_raise
(
rb_eRangeError
,
"%ld..%s%ld out of range"
,
743
origbeg, excl ?
"."
:
""
, origend);
744
}
745
return
Qnil
;
746
}
747
748
/*
749
* call-seq:
750
* rng.to_s -> string
751
*
752
* Convert this range object to a printable form.
753
*/
754
755
static
VALUE
756
range_to_s
(
VALUE
range)
757
{
758
VALUE
str, str2;
759
760
str =
rb_obj_as_string
(
RANGE_BEG
(range));
761
str2 =
rb_obj_as_string
(
RANGE_END
(range));
762
str =
rb_str_dup
(str);
763
rb_str_cat
(str,
"..."
,
EXCL
(range) ? 3 : 2);
764
rb_str_append
(str, str2);
765
OBJ_INFECT
(str, str2);
766
767
return
str;
768
}
769
770
static
VALUE
771
inspect_range
(
VALUE
range,
VALUE
dummy,
int
recur
)
772
{
773
VALUE
str, str2;
774
775
if
(recur) {
776
return
rb_str_new2
(
EXCL
(range) ?
"(... ... ...)"
:
"(... .. ...)"
);
777
}
778
str =
rb_inspect
(
RANGE_BEG
(range));
779
str2 =
rb_inspect
(
RANGE_END
(range));
780
str =
rb_str_dup
(str);
781
rb_str_cat
(str,
"..."
,
EXCL
(range) ? 3 : 2);
782
rb_str_append
(str, str2);
783
OBJ_INFECT
(str, str2);
784
785
return
str;
786
}
787
788
/*
789
* call-seq:
790
* rng.inspect -> string
791
*
792
* Convert this range object to a printable form (using
793
* <code>inspect</code> to convert the start and end
794
* objects).
795
*/
796
797
798
static
VALUE
799
range_inspect
(
VALUE
range)
800
{
801
return
rb_exec_recursive
(
inspect_range
, range, 0);
802
}
803
804
/*
805
* call-seq:
806
* rng === obj -> true or false
807
*
808
* Returns <code>true</code> if <i>obj</i> is an element of
809
* <i>rng</i>, <code>false</code> otherwise. Conveniently,
810
* <code>===</code> is the comparison operator used by
811
* <code>case</code> statements.
812
*
813
* case 79
814
* when 1..50 then print "low\n"
815
* when 51..75 then print "medium\n"
816
* when 76..100 then print "high\n"
817
* end
818
*
819
* <em>produces:</em>
820
*
821
* high
822
*/
823
824
static
VALUE
825
range_eqq
(
VALUE
range,
VALUE
val)
826
{
827
return
rb_funcall
(range,
rb_intern
(
"include?"
), 1, val);
828
}
829
830
831
/*
832
* call-seq:
833
* rng.member?(val) -> true or false
834
* rng.include?(val) -> true or false
835
*
836
* Returns <code>true</code> if <i>obj</i> is an element of
837
* <i>rng</i>, <code>false</code> otherwise. If beg and end are
838
* numeric, comparison is done according magnitude of values.
839
*
840
* ("a".."z").include?("g") # -> true
841
* ("a".."z").include?("A") # -> false
842
*/
843
844
static
VALUE
845
range_include
(
VALUE
range,
VALUE
val)
846
{
847
VALUE
beg =
RANGE_BEG
(range);
848
VALUE
end =
RANGE_END
(range);
849
int
nv =
FIXNUM_P
(beg) ||
FIXNUM_P
(end) ||
850
rb_obj_is_kind_of
(beg,
rb_cNumeric
) ||
851
rb_obj_is_kind_of
(end,
rb_cNumeric
);
852
853
if
(nv ||
854
!
NIL_P
(
rb_check_to_integer
(beg,
"to_int"
)) ||
855
!
NIL_P
(
rb_check_to_integer
(end,
"to_int"
))) {
856
if
(
r_le
(beg, val)) {
857
if
(
EXCL
(range)) {
858
if
(
r_lt
(val, end))
859
return
Qtrue
;
860
}
861
else
{
862
if
(
r_le
(val, end))
863
return
Qtrue
;
864
}
865
}
866
return
Qfalse
;
867
}
868
else
if
(
TYPE
(beg) ==
T_STRING
&&
TYPE
(end) ==
T_STRING
&&
869
RSTRING_LEN
(beg) == 1 &&
RSTRING_LEN
(end) == 1) {
870
if
(
NIL_P
(val))
return
Qfalse
;
871
if
(
TYPE
(val) ==
T_STRING
) {
872
if
(
RSTRING_LEN
(val) == 0 ||
RSTRING_LEN
(val) > 1)
873
return
Qfalse
;
874
else
{
875
char
b =
RSTRING_PTR
(beg)[0];
876
char
e =
RSTRING_PTR
(end)[0];
877
char
v
=
RSTRING_PTR
(val)[0];
878
879
if
(
ISASCII
(b) &&
ISASCII
(e) &&
ISASCII
(v)) {
880
if
(b <= v && v < e)
return
Qtrue
;
881
if
(!
EXCL
(range) && v == e)
return
Qtrue
;
882
return
Qfalse
;
883
}
884
}
885
}
886
}
887
/* TODO: ruby_frame->this_func = rb_intern("include?"); */
888
return
rb_call_super
(1, &val);
889
}
890
891
892
/*
893
* call-seq:
894
* rng.cover?(val) -> true or false
895
*
896
* Returns <code>true</code> if <i>obj</i> is between beg and end,
897
* i.e <code>beg <= obj <= end</code> (or <i>end</i> exclusive when
898
* <code>exclude_end?</code> is true).
899
*
900
* ("a".."z").cover?("c") #=> true
901
* ("a".."z").cover?("5") #=> false
902
*/
903
904
static
VALUE
905
range_cover
(
VALUE
range,
VALUE
val)
906
{
907
VALUE
beg, end;
908
909
beg =
RANGE_BEG
(range);
910
end =
RANGE_END
(range);
911
if
(
r_le
(beg, val)) {
912
if
(
EXCL
(range)) {
913
if
(
r_lt
(val, end))
914
return
Qtrue
;
915
}
916
else
{
917
if
(
r_le
(val, end))
918
return
Qtrue
;
919
}
920
}
921
return
Qfalse
;
922
}
923
924
static
VALUE
925
range_dumper
(
VALUE
range)
926
{
927
VALUE
v
;
928
NEWOBJ
(m,
struct
RObject
);
929
OBJSETUP
(m,
rb_cObject
,
T_OBJECT
);
930
931
v = (
VALUE
)m;
932
933
rb_ivar_set
(v,
id_excl
,
RANGE_EXCL
(range));
934
rb_ivar_set
(v,
id_beg
,
RANGE_BEG
(range));
935
rb_ivar_set
(v,
id_end
,
RANGE_END
(range));
936
return
v
;
937
}
938
939
static
VALUE
940
range_loader
(
VALUE
range,
VALUE
obj)
941
{
942
if
(
TYPE
(obj) !=
T_OBJECT
||
RBASIC
(obj)->klass !=
rb_cObject
) {
943
rb_raise
(
rb_eTypeError
,
"not a dumped range object"
);
944
}
945
946
RSTRUCT
(range)->as.ary[0] =
rb_ivar_get
(obj,
id_beg
);
947
RSTRUCT
(range)->as.ary[1] =
rb_ivar_get
(obj,
id_end
);
948
RSTRUCT
(range)->as.ary[2] =
rb_ivar_get
(obj,
id_excl
);
949
return
range
;
950
}
951
952
static
VALUE
953
range_alloc
(
VALUE
klass)
954
{
955
/* rb_struct_alloc_noinit itself should not be used because
956
* rb_marshal_define_compat uses equality of allocaiton function */
957
return
rb_struct_alloc_noinit
(klass);
958
}
959
960
/* A <code>Range</code> represents an interval---a set of values with a
961
* start and an end. Ranges may be constructed using the
962
* <em>s</em><code>..</code><em>e</em> and
963
* <em>s</em><code>...</code><em>e</em> literals, or with
964
* <code>Range::new</code>. Ranges constructed using <code>..</code>
965
* run from the start to the end inclusively. Those created using
966
* <code>...</code> exclude the end value. When used as an iterator,
967
* ranges return each value in the sequence.
968
*
969
* (-1..-5).to_a #=> []
970
* (-5..-1).to_a #=> [-5, -4, -3, -2, -1]
971
* ('a'..'e').to_a #=> ["a", "b", "c", "d", "e"]
972
* ('a'...'e').to_a #=> ["a", "b", "c", "d"]
973
*
974
* Ranges can be constructed using objects of any type, as long as the
975
* objects can be compared using their <code><=></code> operator and
976
* they support the <code>succ</code> method to return the next object
977
* in sequence.
978
*
979
* class Xs # represent a string of 'x's
980
* include Comparable
981
* attr :length
982
* def initialize(n)
983
* @length = n
984
* end
985
* def succ
986
* Xs.new(@length + 1)
987
* end
988
* def <=>(other)
989
* @length <=> other.length
990
* end
991
* def to_s
992
* sprintf "%2d #{inspect}", @length
993
* end
994
* def inspect
995
* 'x' * @length
996
* end
997
* end
998
*
999
* r = Xs.new(3)..Xs.new(6) #=> xxx..xxxxxx
1000
* r.to_a #=> [xxx, xxxx, xxxxx, xxxxxx]
1001
* r.member?(Xs.new(5)) #=> true
1002
*
1003
* In the previous code example, class <code>Xs</code> includes the
1004
* <code>Comparable</code> module. This is because
1005
* <code>Enumerable#member?</code> checks for equality using
1006
* <code>==</code>. Including <code>Comparable</code> ensures that the
1007
* <code>==</code> method is defined in terms of the <code><=></code>
1008
* method implemented in <code>Xs</code>.
1009
*
1010
*/
1011
1012
void
1013
Init_Range
(
void
)
1014
{
1015
#undef rb_intern
1016
#define rb_intern(str) rb_intern_const(str)
1017
1018
id_cmp
=
rb_intern
(
"<=>"
);
1019
id_succ
=
rb_intern
(
"succ"
);
1020
id_beg
=
rb_intern
(
"begin"
);
1021
id_end
=
rb_intern
(
"end"
);
1022
id_excl
=
rb_intern
(
"excl"
);
1023
1024
rb_cRange
=
rb_struct_define_without_accessor
(
1025
"Range"
,
rb_cObject
,
range_alloc
,
1026
"begin"
,
"end"
,
"excl"
,
NULL
);
1027
1028
rb_include_module
(
rb_cRange
,
rb_mEnumerable
);
1029
rb_marshal_define_compat
(
rb_cRange
,
rb_cObject
,
range_dumper
,
range_loader
);
1030
rb_define_method
(
rb_cRange
,
"initialize"
,
range_initialize
, -1);
1031
rb_define_method
(
rb_cRange
,
"initialize_copy"
,
range_initialize_copy
, 1);
1032
rb_define_method
(
rb_cRange
,
"=="
,
range_eq
, 1);
1033
rb_define_method
(
rb_cRange
,
"==="
,
range_eqq
, 1);
1034
rb_define_method
(
rb_cRange
,
"eql?"
,
range_eql
, 1);
1035
rb_define_method
(
rb_cRange
,
"hash"
,
range_hash
, 0);
1036
rb_define_method
(
rb_cRange
,
"each"
,
range_each
, 0);
1037
rb_define_method
(
rb_cRange
,
"step"
,
range_step
, -1);
1038
rb_define_method
(
rb_cRange
,
"begin"
,
range_begin
, 0);
1039
rb_define_method
(
rb_cRange
,
"end"
,
range_end
, 0);
1040
rb_define_method
(
rb_cRange
,
"first"
,
range_first
, -1);
1041
rb_define_method
(
rb_cRange
,
"last"
,
range_last
, -1);
1042
rb_define_method
(
rb_cRange
,
"min"
,
range_min
, 0);
1043
rb_define_method
(
rb_cRange
,
"max"
,
range_max
, 0);
1044
rb_define_method
(
rb_cRange
,
"to_s"
,
range_to_s
, 0);
1045
rb_define_method
(
rb_cRange
,
"inspect"
,
range_inspect
, 0);
1046
1047
rb_define_method
(
rb_cRange
,
"exclude_end?"
,
range_exclude_end_p
, 0);
1048
1049
rb_define_method
(
rb_cRange
,
"member?"
,
range_include
, 1);
1050
rb_define_method
(
rb_cRange
,
"include?"
,
range_include
, 1);
1051
rb_define_method
(
rb_cRange
,
"cover?"
,
range_cover
, 1);
1052
}
1053
Generated on Fri Jun 28 2013 02:34:42 for Ruby by
1.8.3