00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "ruby.h"
00014
00015 VALUE rb_mComparable;
00016
00017 static ID cmp;
00018
00019 int
00020 rb_cmpint(val, a, b)
00021 VALUE val, a, b;
00022 {
00023 if (NIL_P(val)) {
00024 rb_cmperr(a, b);
00025 }
00026 if (FIXNUM_P(val)) return FIX2INT(val);
00027 if (TYPE(val) == T_BIGNUM) {
00028 if (RBIGNUM(val)->sign) return 1;
00029 return -1;
00030 }
00031 if (RTEST(rb_funcall(val, '>', 1, INT2FIX(0)))) return 1;
00032 if (RTEST(rb_funcall(val, '<', 1, INT2FIX(0)))) return -1;
00033 return 0;
00034 }
00035
00036 void
00037 rb_cmperr(x, y)
00038 VALUE x, y;
00039 {
00040 const char *classname;
00041
00042 if (SPECIAL_CONST_P(y)) {
00043 y = rb_inspect(y);
00044 classname = StringValuePtr(y);
00045 }
00046 else {
00047 classname = rb_obj_classname(y);
00048 }
00049 rb_raise(rb_eArgError, "comparison of %s with %s failed",
00050 rb_obj_classname(x), classname);
00051 }
00052
00053 #define cmperr() (rb_cmperr(x, y), Qnil)
00054
00055 static VALUE
00056 cmp_eq(a)
00057 VALUE *a;
00058 {
00059 VALUE c = rb_funcall(a[0], cmp, 1, a[1]);
00060
00061 if (NIL_P(c)) return Qnil;
00062 if (rb_cmpint(c, a[0], a[1]) == 0) return Qtrue;
00063 return Qfalse;
00064 }
00065
00066 static VALUE
00067 cmp_failed()
00068 {
00069 return Qnil;
00070 }
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081 static VALUE
00082 cmp_equal(x, y)
00083 VALUE x, y;
00084 {
00085 VALUE a[2];
00086
00087 if (x == y) return Qtrue;
00088
00089 a[0] = x; a[1] = y;
00090 return rb_rescue(cmp_eq, (VALUE)a, cmp_failed, 0);
00091 }
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101 static VALUE
00102 cmp_gt(x, y)
00103 VALUE x, y;
00104 {
00105 VALUE c = rb_funcall(x, cmp, 1, y);
00106
00107 if (NIL_P(c)) return cmperr();
00108 if (rb_cmpint(c, x, y) > 0) return Qtrue;
00109 return Qfalse;
00110 }
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120 static VALUE
00121 cmp_ge(x, y)
00122 VALUE x, y;
00123 {
00124 VALUE c = rb_funcall(x, cmp, 1, y);
00125
00126 if (NIL_P(c)) return cmperr();
00127 if (rb_cmpint(c, x, y) >= 0) return Qtrue;
00128 return Qfalse;
00129 }
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 static VALUE
00140 cmp_lt(x, y)
00141 VALUE x, y;
00142 {
00143 VALUE c = rb_funcall(x, cmp, 1, y);
00144
00145 if (NIL_P(c)) return cmperr();
00146 if (rb_cmpint(c, x, y) < 0) return Qtrue;
00147 return Qfalse;
00148 }
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 static VALUE
00160 cmp_le(x, y)
00161 VALUE x, y;
00162 {
00163 VALUE c = rb_funcall(x, cmp, 1, y);
00164
00165 if (NIL_P(c)) return cmperr();
00166 if (rb_cmpint(c, x, y) <= 0) return Qtrue;
00167 return Qfalse;
00168 }
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185 static VALUE
00186 cmp_between(x, min, max)
00187 VALUE x, min, max;
00188 {
00189 if (RTEST(cmp_lt(x, min))) return Qfalse;
00190 if (RTEST(cmp_gt(x, max))) return Qfalse;
00191 return Qtrue;
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231 void
00232 Init_Comparable()
00233 {
00234 rb_mComparable = rb_define_module("Comparable");
00235 rb_define_method(rb_mComparable, "==", cmp_equal, 1);
00236 rb_define_method(rb_mComparable, ">", cmp_gt, 1);
00237 rb_define_method(rb_mComparable, ">=", cmp_ge, 1);
00238 rb_define_method(rb_mComparable, "<", cmp_lt, 1);
00239 rb_define_method(rb_mComparable, "<=", cmp_le, 1);
00240 rb_define_method(rb_mComparable, "between?", cmp_between, 2);
00241
00242 cmp = rb_intern("<=>");
00243 }
00244