Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals

compar.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   compar.c -
00004 
00005   $Author: dave $
00006   $Date: 2003/12/19 00:01:18 $
00007   created at: Thu Aug 26 14:39:48 JST 1993
00008 
00009   Copyright (C) 1993-2003 Yukihiro Matsumoto
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  *  call-seq:
00074  *     obj == other    => true or false
00075  *  
00076  *  Compares two objects based on the receiver's <code><=></code>
00077  *  method, returning true if it returns 0. Also returns true if
00078  *  _obj_ and _other_ are the same object.
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  *  call-seq:
00095  *     obj > other    => true or false
00096  *  
00097  *  Compares two objects based on the receiver's <code><=></code>
00098  *  method, returning true if it returns 1.
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  *  call-seq:
00114  *     obj >= other    => true or false
00115  *  
00116  *  Compares two objects based on the receiver's <code><=></code>
00117  *  method, returning true if it returns 0 or 1.
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  *  call-seq:
00133  *     obj < other    => true or false
00134  *  
00135  *  Compares two objects based on the receiver's <code><=></code>
00136  *  method, returning true if it returns -1.
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  *  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(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  *  call-seq:
00172  *     obj.between?(min, max)    => true or false
00173  *  
00174  *  Returns <code>false</code> if <i>obj</i> <code><=></code>
00175  *  <i>min</i> is less than zero or if <i>anObject</i> <code><=></code>
00176  *  <i>max</i> is greater than zero, <code>true</code> otherwise.
00177  *     
00178  *     3.between?(1, 5)               #=> true
00179  *     6.between?(1, 5)               #=> false
00180  *     'cat'.between?('ant', 'dog')   #=> true
00181  *     'gnu'.between?('ant', 'dog')   #=> false
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  *  The <code>Comparable</code> mixin is used by classes whose objects
00196  *  may be ordered. The class must define the <code><=></code> operator,
00197  *  which compares the receiver against another object, returning -1, 0,
00198  *  or +1 depending on whether the receiver is less than, equal to, or
00199  *  greater than the other object. <code>Comparable</code> uses
00200  *  <code><=></code> to implement the conventional comparison operators
00201  *  (<code><</code>, <code><=</code>, <code>==</code>, <code>>=</code>,
00202  *  and <code>></code>) and the method <code>between?</code>.
00203  *     
00204  *     class SizeMatters
00205  *       include Comparable
00206  *       attr :str
00207  *       def <=>(anOther)
00208  *         str.size <=> anOther.str.size
00209  *       end
00210  *       def initialize(str)
00211  *         @str = str
00212  *       end
00213  *       def inspect
00214  *         @str
00215  *       end
00216  *     end
00217  *     
00218  *     s1 = SizeMatters.new("Z")
00219  *     s2 = SizeMatters.new("YY")
00220  *     s3 = SizeMatters.new("XXX")
00221  *     s4 = SizeMatters.new("WWWW")
00222  *     s5 = SizeMatters.new("VVVVV")
00223  *     
00224  *     s1 < s2                       #=> true
00225  *     s4.between?(s1, s3)           #=> false
00226  *     s4.between?(s3, s5)           #=> true
00227  *     [ s3, s2, s5, s4, s1 ].sort   #=> [Z, YY, XXX, WWWW, VVVVV]
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 

Generated on Wed Jan 18 23:31:58 2006 for Ruby by doxygen 1.3.5