• 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 

Generated on Sat Jul 7 2012 15:26:29 for Ruby by  doxygen 1.7.1