Permalink
Newer
Older
100644 244 lines (207 sloc) 5.41 KB
May 1, 2000
1
/**********************************************************************
Jan 16, 1998
2
3
compar.c -
4
5
$Author$
6
$Date$
7
created at: Thu Aug 26 14:39:48 JST 1993
8
9
Copyright (C) 1993-2003 Yukihiro Matsumoto
Jan 16, 1998
10
May 1, 2000
11
**********************************************************************/
Jan 16, 1998
12
13
#include "ruby.h"
14
Jan 16, 1998
16
17
static ID cmp;
18
20
rb_cmpint(val, a, b)
21
VALUE val, a, b;
23
if (NIL_P(val)) {
24
rb_cmperr(a, b);
25
}
26
if (FIXNUM_P(val)) return FIX2INT(val);
27
if (TYPE(val) == T_BIGNUM) {
28
if (RBIGNUM(val)->sign) return 1;
29
return -1;
30
}
31
if (RTEST(rb_funcall(val, '>', 1, INT2FIX(0)))) return 1;
32
if (RTEST(rb_funcall(val, '<', 1, INT2FIX(0)))) return -1;
33
return 0;
34
}
35
36
void
37
rb_cmperr(x, y)
38
VALUE x, y;
40
const char *classname;
41
42
if (SPECIAL_CONST_P(y)) {
43
y = rb_inspect(y);
44
classname = StringValuePtr(y);
45
}
46
else {
47
classname = rb_obj_classname(y);
48
}
49
rb_raise(rb_eArgError, "comparison of %s with %s failed",
50
rb_obj_classname(x), classname);
53
#define cmperr() (rb_cmperr(x, y), Qnil)
54
Oct 30, 2003
55
static VALUE
56
cmp_eq(a)
57
VALUE *a;
58
{
59
VALUE c = rb_funcall(a[0], cmp, 1, a[1]);
60
61
if (NIL_P(c)) return Qnil;
62
if (rb_cmpint(c, a[0], a[1]) == 0) return Qtrue;
63
return Qfalse;
64
}
65
66
static VALUE
67
cmp_failed()
68
{
69
return Qnil;
70
}
71
dave
Dec 19, 2003
72
/*
73
* call-seq:
74
* obj == other => true or false
75
*
76
* Compares two objects based on the receiver's <code><=></code>
77
* method, returning true if it returns 0. Also returns true if
78
* _obj_ and _other_ are the same object.
79
*/
80
Sep 16, 1999
81
static VALUE
82
cmp_equal(x, y)
83
VALUE x, y;
84
{
Oct 30, 2003
85
VALUE a[2];
Sep 16, 1999
86
Oct 30, 2003
89
a[0] = x; a[1] = y;
90
return rb_rescue(cmp_eq, (VALUE)a, cmp_failed, 0);
Sep 16, 1999
91
}
92
dave
Dec 19, 2003
93
/*
94
* call-seq:
95
* obj > other => true or false
96
*
97
* Compares two objects based on the receiver's <code><=></code>
98
* method, returning true if it returns 1.
99
*/
100
Jan 16, 1998
101
static VALUE
102
cmp_gt(x, y)
103
VALUE x, y;
104
{
105
VALUE c = rb_funcall(x, cmp, 1, y);
106
107
if (NIL_P(c)) return cmperr();
108
if (rb_cmpint(c, x, y) > 0) return Qtrue;
Jan 16, 1998
110
}
111
dave
Dec 19, 2003
112
/*
113
* call-seq:
114
* obj >= other => true or false
115
*
116
* Compares two objects based on the receiver's <code><=></code>
117
* method, returning true if it returns 0 or 1.
118
*/
119
Jan 16, 1998
120
static VALUE
121
cmp_ge(x, y)
122
VALUE x, y;
123
{
124
VALUE c = rb_funcall(x, cmp, 1, y);
125
126
if (NIL_P(c)) return cmperr();
127
if (rb_cmpint(c, x, y) >= 0) return Qtrue;
Jan 16, 1998
129
}
130
dave
Dec 19, 2003
131
/*
132
* call-seq:
133
* obj < other => true or false
134
*
135
* Compares two objects based on the receiver's <code><=></code>
136
* method, returning true if it returns -1.
137
*/
138
Jan 16, 1998
139
static VALUE
140
cmp_lt(x, y)
141
VALUE x, y;
142
{
143
VALUE c = rb_funcall(x, cmp, 1, y);
144
145
if (NIL_P(c)) return cmperr();
146
if (rb_cmpint(c, x, y) < 0) return Qtrue;
Jan 16, 1998
148
}
149
dave
Dec 19, 2003
150
151
/*
152
* call-seq:
153
* obj <= other => true or false
154
*
155
* Compares two objects based on the receiver's <code><=></code>
156
* method, returning true if it returns -1 or 0.
157
*/
158
Jan 16, 1998
159
static VALUE
160
cmp_le(x, y)
161
VALUE x, y;
162
{
163
VALUE c = rb_funcall(x, cmp, 1, y);
164
165
if (NIL_P(c)) return cmperr();
166
if (rb_cmpint(c, x, y) <= 0) return Qtrue;
Jan 16, 1998
168
}
169
dave
Dec 19, 2003
170
/*
171
* call-seq:
172
* obj.between?(min, max) => true or false
173
*
174
* Returns <code>false</code> if <i>obj</i> <code><=></code>
175
* <i>min</i> is less than zero or if <i>anObject</i> <code><=></code>
176
* <i>max</i> is greater than zero, <code>true</code> otherwise.
177
*
178
* 3.between?(1, 5) #=> true
179
* 6.between?(1, 5) #=> false
180
* 'cat'.between?('ant', 'dog') #=> true
181
* 'gnu'.between?('ant', 'dog') #=> false
182
*
183
*/
184
Jan 16, 1998
185
static VALUE
186
cmp_between(x, min, max)
187
VALUE x, min, max;
188
{
189
if (RTEST(cmp_lt(x, min))) return Qfalse;
190
if (RTEST(cmp_gt(x, max))) return Qfalse;
Jan 16, 1998
192
}
193
dave
Dec 19, 2003
194
/*
195
* The <code>Comparable</code> mixin is used by classes whose objects
196
* may be ordered. The class must define the <code><=></code> operator,
197
* which compares the receiver against another object, returning -1, 0,
198
* or +1 depending on whether the receiver is less than, equal to, or
199
* greater than the other object. <code>Comparable</code> uses
200
* <code><=></code> to implement the conventional comparison operators
201
* (<code><</code>, <code><=</code>, <code>==</code>, <code>>=</code>,
202
* and <code>></code>) and the method <code>between?</code>.
203
*
204
* class SizeMatters
205
* include Comparable
206
* attr :str
207
* def <=>(anOther)
208
* str.size <=> anOther.str.size
209
* end
210
* def initialize(str)
211
* @str = str
212
* end
213
* def inspect
214
* @str
215
* end
216
* end
217
*
218
* s1 = SizeMatters.new("Z")
219
* s2 = SizeMatters.new("YY")
220
* s3 = SizeMatters.new("XXX")
221
* s4 = SizeMatters.new("WWWW")
222
* s5 = SizeMatters.new("VVVVV")
223
*
224
* s1 < s2 #=> true
225
* s4.between?(s1, s3) #=> false
226
* s4.between?(s3, s5) #=> true
227
* [ s3, s2, s5, s4, s1 ].sort #=> [Z, YY, XXX, WWWW, VVVVV]
228
*
229
*/
230
Jan 16, 1998
231
void
232
Init_Comparable()
233
{
234
rb_mComparable = rb_define_module("Comparable");
Sep 16, 1999
235
rb_define_method(rb_mComparable, "==", cmp_equal, 1);
236
rb_define_method(rb_mComparable, ">", cmp_gt, 1);
237
rb_define_method(rb_mComparable, ">=", cmp_ge, 1);
238
rb_define_method(rb_mComparable, "<", cmp_lt, 1);
239
rb_define_method(rb_mComparable, "<=", cmp_le, 1);
240
rb_define_method(rb_mComparable, "between?", cmp_between, 2);
Jan 16, 1998
241
242
cmp = rb_intern("<=>");
243
}