|
Ruby
1.9.3p537(2014-02-19revision0)
|
00001 /********************************************************************** 00002 00003 compar.c - 00004 00005 $Author$ 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 cmp_eq_recursive(VALUE arg1, VALUE arg2, int recursive) 00036 { 00037 if (recursive) return Qfalse; 00038 return rb_funcall2(arg1, cmp, 1, &arg2); 00039 } 00040 00041 static VALUE 00042 cmp_eq(VALUE *a) 00043 { 00044 VALUE c = rb_exec_recursive_paired_outer(cmp_eq_recursive, a[0], a[1], a[1]); 00045 00046 if (NIL_P(c)) return Qfalse; 00047 if (rb_cmpint(c, a[0], a[1]) == 0) return Qtrue; 00048 return Qfalse; 00049 } 00050 00051 static VALUE 00052 cmp_failed(void) 00053 { 00054 return Qfalse; 00055 } 00056 00057 /* 00058 * call-seq: 00059 * obj == other -> true or false 00060 * 00061 * Compares two objects based on the receiver's <code><=></code> 00062 * method, returning true if it returns 0. Also returns true if 00063 * _obj_ and _other_ are the same object. 00064 */ 00065 00066 static VALUE 00067 cmp_equal(VALUE x, VALUE y) 00068 { 00069 VALUE a[2]; 00070 00071 if (x == y) return Qtrue; 00072 00073 a[0] = x; a[1] = y; 00074 return rb_rescue(cmp_eq, (VALUE)a, cmp_failed, 0); 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 1. 00083 */ 00084 00085 static VALUE 00086 cmp_gt(VALUE x, VALUE y) 00087 { 00088 VALUE c = rb_funcall(x, cmp, 1, y); 00089 00090 if (rb_cmpint(c, x, y) > 0) return Qtrue; 00091 return Qfalse; 00092 } 00093 00094 /* 00095 * call-seq: 00096 * obj >= other -> true or false 00097 * 00098 * Compares two objects based on the receiver's <code><=></code> 00099 * method, returning true if it returns 0 or 1. 00100 */ 00101 00102 static VALUE 00103 cmp_ge(VALUE x, VALUE y) 00104 { 00105 VALUE c = rb_funcall(x, cmp, 1, y); 00106 00107 if (rb_cmpint(c, x, y) >= 0) return Qtrue; 00108 return Qfalse; 00109 } 00110 00111 /* 00112 * call-seq: 00113 * obj < other -> true or false 00114 * 00115 * Compares two objects based on the receiver's <code><=></code> 00116 * method, returning true if it returns -1. 00117 */ 00118 00119 static VALUE 00120 cmp_lt(VALUE x, VALUE y) 00121 { 00122 VALUE c = rb_funcall(x, cmp, 1, y); 00123 00124 if (rb_cmpint(c, x, y) < 0) return Qtrue; 00125 return Qfalse; 00126 } 00127 00128 /* 00129 * call-seq: 00130 * obj <= other -> true or false 00131 * 00132 * Compares two objects based on the receiver's <code><=></code> 00133 * method, returning true if it returns -1 or 0. 00134 */ 00135 00136 static VALUE 00137 cmp_le(VALUE x, VALUE y) 00138 { 00139 VALUE c = rb_funcall(x, cmp, 1, y); 00140 00141 if (rb_cmpint(c, x, y) <= 0) return Qtrue; 00142 return Qfalse; 00143 } 00144 00145 /* 00146 * call-seq: 00147 * obj.between?(min, max) -> true or false 00148 * 00149 * Returns <code>false</code> if <i>obj</i> <code><=></code> 00150 * <i>min</i> is less than zero or if <i>anObject</i> <code><=></code> 00151 * <i>max</i> is greater than zero, <code>true</code> otherwise. 00152 * 00153 * 3.between?(1, 5) #=> true 00154 * 6.between?(1, 5) #=> false 00155 * 'cat'.between?('ant', 'dog') #=> true 00156 * 'gnu'.between?('ant', 'dog') #=> false 00157 * 00158 */ 00159 00160 static VALUE 00161 cmp_between(VALUE x, VALUE min, VALUE max) 00162 { 00163 if (RTEST(cmp_lt(x, min))) return Qfalse; 00164 if (RTEST(cmp_gt(x, max))) return Qfalse; 00165 return Qtrue; 00166 } 00167 00168 /* 00169 * The <code>Comparable</code> mixin is used by classes whose objects 00170 * may be ordered. The class must define the <code><=></code> operator, 00171 * which compares the receiver against another object, returning -1, 0, 00172 * or +1 depending on whether the receiver is less than, equal to, or 00173 * greater than the other object. If the other object is not comparable 00174 * then the <code><=></code> operator should return nil. 00175 * <code>Comparable</code> uses 00176 * <code><=></code> to implement the conventional comparison operators 00177 * (<code><</code>, <code><=</code>, <code>==</code>, <code>>=</code>, 00178 * and <code>></code>) and the method <code>between?</code>. 00179 * 00180 * class SizeMatters 00181 * include Comparable 00182 * attr :str 00183 * def <=>(anOther) 00184 * str.size <=> anOther.str.size 00185 * end 00186 * def initialize(str) 00187 * @str = str 00188 * end 00189 * def inspect 00190 * @str 00191 * end 00192 * end 00193 * 00194 * s1 = SizeMatters.new("Z") 00195 * s2 = SizeMatters.new("YY") 00196 * s3 = SizeMatters.new("XXX") 00197 * s4 = SizeMatters.new("WWWW") 00198 * s5 = SizeMatters.new("VVVVV") 00199 * 00200 * s1 < s2 #=> true 00201 * s4.between?(s1, s3) #=> false 00202 * s4.between?(s3, s5) #=> true 00203 * [ s3, s2, s5, s4, s1 ].sort #=> [Z, YY, XXX, WWWW, VVVVV] 00204 * 00205 */ 00206 00207 void 00208 Init_Comparable(void) 00209 { 00210 #undef rb_intern 00211 #define rb_intern(str) rb_intern_const(str) 00212 00213 rb_mComparable = rb_define_module("Comparable"); 00214 rb_define_method(rb_mComparable, "==", cmp_equal, 1); 00215 rb_define_method(rb_mComparable, ">", cmp_gt, 1); 00216 rb_define_method(rb_mComparable, ">=", cmp_ge, 1); 00217 rb_define_method(rb_mComparable, "<", cmp_lt, 1); 00218 rb_define_method(rb_mComparable, "<=", cmp_le, 1); 00219 rb_define_method(rb_mComparable, "between?", cmp_between, 2); 00220 00221 cmp = rb_intern("<=>"); 00222 } 00223
1.7.6.1