00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "ruby/ruby.h"
00013
00014 VALUE rb_mComparable;
00015
00016 static ID cmp;
00017
00018 void
00019 rb_cmperr(VALUE x, VALUE y)
00020 {
00021 const char *classname;
00022
00023 if (SPECIAL_CONST_P(y) || BUILTIN_TYPE(y) == T_FLOAT) {
00024 y = rb_inspect(y);
00025 classname = StringValuePtr(y);
00026 }
00027 else {
00028 classname = rb_obj_classname(y);
00029 }
00030 rb_raise(rb_eArgError, "comparison of %s with %s failed",
00031 rb_obj_classname(x), classname);
00032 }
00033
00034 static VALUE
00035 invcmp_recursive(VALUE x, VALUE y, int recursive)
00036 {
00037 if (recursive) return Qnil;
00038 return rb_check_funcall(y, cmp, 1, &x);
00039 }
00040
00041 VALUE
00042 rb_invcmp(VALUE x, VALUE y)
00043 {
00044 VALUE invcmp = rb_exec_recursive(invcmp_recursive, x, y);
00045 if (invcmp == Qundef || NIL_P(invcmp)) {
00046 return Qnil;
00047 }
00048 else {
00049 int result = -rb_cmpint(invcmp, x, y);
00050 return INT2FIX(result);
00051 }
00052 }
00053
00054 static VALUE
00055 cmp_eq_recursive(VALUE arg1, VALUE arg2, int recursive)
00056 {
00057 if (recursive) return Qfalse;
00058 return rb_funcall(arg1, cmp, 1, arg2);
00059 }
00060
00061 static VALUE
00062 cmp_eq(VALUE *a)
00063 {
00064 VALUE c = rb_exec_recursive_paired_outer(cmp_eq_recursive, a[0], a[1], a[1]);
00065
00066 if (NIL_P(c)) return Qfalse;
00067 if (rb_cmpint(c, a[0], a[1]) == 0) return Qtrue;
00068 return Qfalse;
00069 }
00070
00071 static VALUE
00072 cmp_failed(void)
00073 {
00074 return Qfalse;
00075 }
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 static VALUE
00090 cmp_equal(VALUE x, VALUE y)
00091 {
00092 VALUE a[2];
00093
00094 if (x == y) return Qtrue;
00095
00096 a[0] = x; a[1] = y;
00097 return rb_rescue(cmp_eq, (VALUE)a, cmp_failed, 0);
00098 }
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108 static VALUE
00109 cmp_gt(VALUE x, VALUE y)
00110 {
00111 VALUE c = rb_funcall(x, cmp, 1, y);
00112
00113 if (rb_cmpint(c, x, y) > 0) return Qtrue;
00114 return Qfalse;
00115 }
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125 static VALUE
00126 cmp_ge(VALUE x, VALUE y)
00127 {
00128 VALUE c = rb_funcall(x, cmp, 1, y);
00129
00130 if (rb_cmpint(c, x, y) >= 0) return Qtrue;
00131 return Qfalse;
00132 }
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 static VALUE
00143 cmp_lt(VALUE x, VALUE y)
00144 {
00145 VALUE c = rb_funcall(x, cmp, 1, y);
00146
00147 if (rb_cmpint(c, x, y) < 0) return Qtrue;
00148 return Qfalse;
00149 }
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 static VALUE
00160 cmp_le(VALUE x, VALUE y)
00161 {
00162 VALUE c = rb_funcall(x, cmp, 1, y);
00163
00164 if (rb_cmpint(c, x, y) <= 0) return Qtrue;
00165 return Qfalse;
00166 }
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183 static VALUE
00184 cmp_between(VALUE x, VALUE min, VALUE max)
00185 {
00186 if (RTEST(cmp_lt(x, min))) return Qfalse;
00187 if (RTEST(cmp_gt(x, max))) return Qfalse;
00188 return Qtrue;
00189 }
00190
00191
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 void
00231 Init_Comparable(void)
00232 {
00233 #undef rb_intern
00234 #define rb_intern(str) rb_intern_const(str)
00235
00236 rb_mComparable = rb_define_module("Comparable");
00237 rb_define_method(rb_mComparable, "==", cmp_equal, 1);
00238 rb_define_method(rb_mComparable, ">", cmp_gt, 1);
00239 rb_define_method(rb_mComparable, ">=", cmp_ge, 1);
00240 rb_define_method(rb_mComparable, "<", cmp_lt, 1);
00241 rb_define_method(rb_mComparable, "<=", cmp_le, 1);
00242 rb_define_method(rb_mComparable, "between?", cmp_between, 2);
00243
00244 cmp = rb_intern("<=>");
00245 }
00246