Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# compar.c

Go to the documentation of this file.

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