1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13: #include "ruby/ruby.h"
14:
15: VALUE rb_mComparable;
16:
17: static ID cmp;
18:
19: int
20: rb_cmpint(VALUE val, VALUE a, VALUE b)
21: {
22: if (NIL_P(val)) {
23: rb_cmperr(a, b);
24: }
25: if (FIXNUM_P(val)) return FIX2INT(val);
26: if (TYPE(val) == T_BIGNUM) {
27: if (RBIGNUM_SIGN(val)) return 1;
28: return -1;
29: }
30: if (RTEST(rb_funcall(val, '>', 1, INT2FIX(0)))) return 1;
31: if (RTEST(rb_funcall(val, '<', 1, INT2FIX(0)))) return -1;
32: return 0;
33: }
34:
35: void
36: rb_cmperr(VALUE x, VALUE y)
37: {
38: const char *classname;
39:
40: if (SPECIAL_CONST_P(y)) {
41: y = rb_inspect(y);
42: classname = StringValuePtr(y);
43: }
44: else {
45: classname = rb_obj_classname(y);
46: }
47: rb_raise(rb_eArgError, "comparison of %s with %s failed",
48: rb_obj_classname(x), classname);
49: }
50:
51: static VALUE
52: cmp_eq(VALUE *a)
53: {
54: VALUE c = rb_funcall(a[0], cmp, 1, a[1]);
55:
56: if (NIL_P(c)) return Qfalse;
57: if (rb_cmpint(c, a[0], a[1]) == 0) return Qtrue;
58: return Qfalse;
59: }
60:
61: static VALUE
62: cmp_failed(void)
63: {
64: return Qfalse;
65: }
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76: static VALUE
77: cmp_equal(VALUE x, VALUE y)
78: {
79: VALUE a[2];
80:
81: if (x == y) return Qtrue;
82:
83: a[0] = x; a[1] = y;
84: return rb_rescue(cmp_eq, (VALUE)a, cmp_failed, 0);
85: }
86:
87:
88:
89:
90:
91:
92:
93:
94:
95: static VALUE
96: cmp_gt(VALUE x, VALUE y)
97: {
98: VALUE c = rb_funcall(x, cmp, 1, y);
99:
100: if (rb_cmpint(c, x, y) > 0) return Qtrue;
101: return Qfalse;
102: }
103:
104:
105:
106:
107:
108:
109:
110:
111:
112: static VALUE
113: cmp_ge(VALUE x, VALUE y)
114: {
115: VALUE c = rb_funcall(x, cmp, 1, y);
116:
117: if (rb_cmpint(c, x, y) >= 0) return Qtrue;
118: return Qfalse;
119: }
120:
121:
122:
123:
124:
125:
126:
127:
128:
129: static VALUE
130: cmp_lt(VALUE x, VALUE y)
131: {
132: VALUE c = rb_funcall(x, cmp, 1, y);
133:
134: if (rb_cmpint(c, x, y) < 0) return Qtrue;
135: return Qfalse;
136: }
137:
138:
139:
140:
141:
142:
143:
144:
145:
146: static VALUE
147: cmp_le(VALUE x, VALUE y)
148: {
149: VALUE c = rb_funcall(x, cmp, 1, y);
150:
151: if (rb_cmpint(c, x, y) <= 0) return Qtrue;
152: return Qfalse;
153: }
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170: static VALUE
171: cmp_between(VALUE x, VALUE min, VALUE max)
172: {
173: if (RTEST(cmp_lt(x, min))) return Qfalse;
174: if (RTEST(cmp_gt(x, max))) return Qfalse;
175: return Qtrue;
176: }
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215: void
216: Init_Comparable(void)
217: {
218: rb_mComparable = rb_define_module("Comparable");
219: rb_define_method(rb_mComparable, "==", cmp_equal, 1);
220: rb_define_method(rb_mComparable, ">", cmp_gt, 1);
221: rb_define_method(rb_mComparable, ">=", cmp_ge, 1);
222: rb_define_method(rb_mComparable, "<", cmp_lt, 1);
223: rb_define_method(rb_mComparable, "<=", cmp_le, 1);
224: rb_define_method(rb_mComparable, "between?", cmp_between, 2);
225:
226: cmp = rb_intern("<=>");
227: }