|
Ruby
2.0.0p481(2014-05-08revision45883)
|
00001 /********************************************************************** 00002 00003 compar.c - 00004 00005 $Author: nagachika $ 00006 created at: Thu Aug 26 14:39:48 JST 1993 00007 00008 Copyright (C) 1993-2007 Yukihiro Matsumoto 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)) { 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 * call-seq: 00079 * obj == other -> true or false 00080 * 00081 * Compares two objects based on the receiver's <code><=></code> 00082 * method, returning true if it returns 0. Also returns true if 00083 * _obj_ and _other_ are the same object. 00084 * 00085 * Even if _obj_ <=> _other_ raised an exception, the exception 00086 * is ignoread and returns false. 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 * call-seq: 00102 * obj > other -> true or false 00103 * 00104 * Compares two objects based on the receiver's <code><=></code> 00105 * method, returning true if it returns 1. 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 * call-seq: 00119 * obj >= other -> true or false 00120 * 00121 * Compares two objects based on the receiver's <code><=></code> 00122 * method, returning true if it returns 0 or 1. 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 * call-seq: 00136 * obj < other -> true or false 00137 * 00138 * Compares two objects based on the receiver's <code><=></code> 00139 * method, returning true if it returns -1. 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 * call-seq: 00153 * obj <= other -> true or false 00154 * 00155 * Compares two objects based on the receiver's <code><=></code> 00156 * method, returning true if it returns -1 or 0. 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 * call-seq: 00170 * obj.between?(min, max) -> true or false 00171 * 00172 * Returns <code>false</code> if <i>obj</i> <code><=></code> 00173 * <i>min</i> is less than zero or if <i>anObject</i> <code><=></code> 00174 * <i>max</i> is greater than zero, <code>true</code> otherwise. 00175 * 00176 * 3.between?(1, 5) #=> true 00177 * 6.between?(1, 5) #=> false 00178 * 'cat'.between?('ant', 'dog') #=> true 00179 * 'gnu'.between?('ant', 'dog') #=> false 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 * The <code>Comparable</code> mixin is used by classes whose objects 00193 * may be ordered. The class must define the <code><=></code> operator, 00194 * which compares the receiver against another object, returning -1, 0, 00195 * or +1 depending on whether the receiver is less than, equal to, or 00196 * greater than the other object. If the other object is not comparable 00197 * then the <code><=></code> operator should return nil. 00198 * <code>Comparable</code> uses 00199 * <code><=></code> to implement the conventional comparison operators 00200 * (<code><</code>, <code><=</code>, <code>==</code>, <code>>=</code>, 00201 * and <code>></code>) and the method <code>between?</code>. 00202 * 00203 * class SizeMatters 00204 * include Comparable 00205 * attr :str 00206 * def <=>(anOther) 00207 * str.size <=> anOther.str.size 00208 * end 00209 * def initialize(str) 00210 * @str = str 00211 * end 00212 * def inspect 00213 * @str 00214 * end 00215 * end 00216 * 00217 * s1 = SizeMatters.new("Z") 00218 * s2 = SizeMatters.new("YY") 00219 * s3 = SizeMatters.new("XXX") 00220 * s4 = SizeMatters.new("WWWW") 00221 * s5 = SizeMatters.new("VVVVV") 00222 * 00223 * s1 < s2 #=> true 00224 * s4.between?(s1, s3) #=> false 00225 * s4.between?(s3, s5) #=> true 00226 * [ s3, s2, s5, s4, s1 ].sort #=> [Z, YY, XXX, WWWW, VVVVV] 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
1.7.6.1