(linenum→info "unix/slp.c:2238")

ruby/1.9.0/compar.c

    1: /**********************************************************************
    2: 
    3:   compar.c -
    4: 
    5:   $Author: akr $
    6:   $Date: 2007-09-01 21:02:36 +0900 (Sat, 01 Sep 2007) $
    7:   created at: Thu Aug 26 14:39:48 JST 1993
    8: 
    9:   Copyright (C) 1993-2007 Yukihiro Matsumoto
   10: 
   11: **********************************************************************/
   12: 
   13: #include "ruby/ruby.h"
   14: 
   15: VALUE rb_mComparable;
   16: 
   17: static ID cmp;
   18: 
   19: int
   20: rb_cmpint(VALUE val, VALUE a, VALUE b)
   21: {
   22:     if (NIL_P(val)) {
   23:         rb_cmperr(a, b);
   24:     }
   25:     if (FIXNUM_P(val)) return FIX2INT(val);
   26:     if (TYPE(val) == T_BIGNUM) {
   27:         if (RBIGNUM_SIGN(val)) return 1;
   28:         return -1;
   29:     }
   30:     if (RTEST(rb_funcall(val, '>', 1, INT2FIX(0)))) return 1;
   31:     if (RTEST(rb_funcall(val, '<', 1, INT2FIX(0)))) return -1;
   32:     return 0;
   33: }
   34: 
   35: void
   36: rb_cmperr(VALUE x, VALUE y)
   37: {
   38:     const char *classname;
   39: 
   40:     if (SPECIAL_CONST_P(y)) {
   41:         y = rb_inspect(y);
   42:         classname = StringValuePtr(y);
   43:     }
   44:     else {
   45:         classname = rb_obj_classname(y);
   46:     }
   47:     rb_raise(rb_eArgError, "comparison of %s with %s failed",
   48:              rb_obj_classname(x), classname);
   49: }
   50: 
   51: static VALUE
   52: cmp_eq(VALUE *a)
   53: {
   54:     VALUE c = rb_funcall(a[0], cmp, 1, a[1]);
   55: 
   56:     if (NIL_P(c)) return Qfalse;
   57:     if (rb_cmpint(c, a[0], a[1]) == 0) return Qtrue;
   58:     return Qfalse;
   59: }
   60: 
   61: static VALUE
   62: cmp_failed(void)
   63: {
   64:     return Qfalse;
   65: }
   66: 
   67: /*
   68:  *  call-seq:
   69:  *     obj == other    => true or false
   70:  *  
   71:  *  Compares two objects based on the receiver's <code><=></code>
   72:  *  method, returning true if it returns 0. Also returns true if
   73:  *  _obj_ and _other_ are the same object.
   74:  */
   75: 
   76: static VALUE
   77: cmp_equal(VALUE x, VALUE y)
   78: {
   79:     VALUE a[2];
   80: 
   81:     if (x == y) return Qtrue;
   82: 
   83:     a[0] = x; a[1] = y;
   84:     return rb_rescue(cmp_eq, (VALUE)a, cmp_failed, 0);
   85: }
   86: 
   87: /*
   88:  *  call-seq:
   89:  *     obj > other    => true or false
   90:  *  
   91:  *  Compares two objects based on the receiver's <code><=></code>
   92:  *  method, returning true if it returns 1.
   93:  */
   94: 
   95: static VALUE
   96: cmp_gt(VALUE x, VALUE y)
   97: {
   98:     VALUE c = rb_funcall(x, cmp, 1, y);
   99: 
  100:     if (rb_cmpint(c, x, y) > 0) return Qtrue;
  101:     return Qfalse;
  102: }
  103: 
  104: /*
  105:  *  call-seq:
  106:  *     obj >= other    => true or false
  107:  *  
  108:  *  Compares two objects based on the receiver's <code><=></code>
  109:  *  method, returning true if it returns 0 or 1.
  110:  */
  111: 
  112: static VALUE
  113: cmp_ge(VALUE x, VALUE y)
  114: {
  115:     VALUE c = rb_funcall(x, cmp, 1, y);
  116: 
  117:     if (rb_cmpint(c, x, y) >= 0) return Qtrue;
  118:     return Qfalse;
  119: }
  120: 
  121: /*
  122:  *  call-seq:
  123:  *     obj < other    => true or false
  124:  *  
  125:  *  Compares two objects based on the receiver's <code><=></code>
  126:  *  method, returning true if it returns -1.
  127:  */
  128: 
  129: static VALUE
  130: cmp_lt(VALUE x, VALUE y)
  131: {
  132:     VALUE c = rb_funcall(x, cmp, 1, y);
  133: 
  134:     if (rb_cmpint(c, x, y) < 0) return Qtrue;
  135:     return Qfalse;
  136: }
  137: 
  138: /*
  139:  *  call-seq:
  140:  *     obj <= other    => true or false
  141:  *  
  142:  *  Compares two objects based on the receiver's <code><=></code>
  143:  *  method, returning true if it returns -1 or 0.
  144:  */
  145: 
  146: static VALUE
  147: cmp_le(VALUE x, VALUE y)
  148: {
  149:     VALUE c = rb_funcall(x, cmp, 1, y);
  150: 
  151:     if (rb_cmpint(c, x, y) <= 0) return Qtrue;
  152:     return Qfalse;
  153: }
  154: 
  155: /*
  156:  *  call-seq:
  157:  *     obj.between?(min, max)    => true or false
  158:  *  
  159:  *  Returns <code>false</code> if <i>obj</i> <code><=></code>
  160:  *  <i>min</i> is less than zero or if <i>anObject</i> <code><=></code>
  161:  *  <i>max</i> is greater than zero, <code>true</code> otherwise.
  162:  *     
  163:  *     3.between?(1, 5)               #=> true
  164:  *     6.between?(1, 5)               #=> false
  165:  *     'cat'.between?('ant', 'dog')   #=> true
  166:  *     'gnu'.between?('ant', 'dog')   #=> false
  167:  *     
  168:  */
  169: 
  170: static VALUE
  171: cmp_between(VALUE x, VALUE min, VALUE max)
  172: {
  173:     if (RTEST(cmp_lt(x, min))) return Qfalse;
  174:     if (RTEST(cmp_gt(x, max))) return Qfalse;
  175:     return Qtrue;
  176: }
  177: 
  178: /*
  179:  *  The <code>Comparable</code> mixin is used by classes whose objects
  180:  *  may be ordered. The class must define the <code><=></code> operator,
  181:  *  which compares the receiver against another object, returning -1, 0,
  182:  *  or +1 depending on whether the receiver is less than, equal to, or
  183:  *  greater than the other object. <code>Comparable</code> uses
  184:  *  <code><=></code> to implement the conventional comparison operators
  185:  *  (<code><</code>, <code><=</code>, <code>==</code>, <code>>=</code>,
  186:  *  and <code>></code>) and the method <code>between?</code>.
  187:  *     
  188:  *     class SizeMatters
  189:  *       include Comparable
  190:  *       attr :str
  191:  *       def <=>(anOther)
  192:  *         str.size <=> anOther.str.size
  193:  *       end
  194:  *       def initialize(str)
  195:  *         @str = str
  196:  *       end
  197:  *       def inspect
  198:  *         @str
  199:  *       end
  200:  *     end
  201:  *     
  202:  *     s1 = SizeMatters.new("Z")
  203:  *     s2 = SizeMatters.new("YY")
  204:  *     s3 = SizeMatters.new("XXX")
  205:  *     s4 = SizeMatters.new("WWWW")
  206:  *     s5 = SizeMatters.new("VVVVV")
  207:  *     
  208:  *     s1 < s2                       #=> true
  209:  *     s4.between?(s1, s3)           #=> false
  210:  *     s4.between?(s3, s5)           #=> true
  211:  *     [ s3, s2, s5, s4, s1 ].sort   #=> [Z, YY, XXX, WWWW, VVVVV]
  212:  *     
  213:  */
  214: 
  215: void
  216: Init_Comparable(void)
  217: {
  218:     rb_mComparable = rb_define_module("Comparable");
  219:     rb_define_method(rb_mComparable, "==", cmp_equal, 1);
  220:     rb_define_method(rb_mComparable, ">", cmp_gt, 1);
  221:     rb_define_method(rb_mComparable, ">=", cmp_ge, 1);
  222:     rb_define_method(rb_mComparable, "<", cmp_lt, 1);
  223:     rb_define_method(rb_mComparable, "<=", cmp_le, 1);
  224:     rb_define_method(rb_mComparable, "between?", cmp_between, 2);
  225: 
  226:     cmp = rb_intern("<=>");
  227: }
Syntax (Markdown)