Ruby  2.0.0p247(2013-06-27revision41674)
compar.c
Go to the documentation of this file.
1 /**********************************************************************
2 
3  compar.c -
4 
5  $Author: drbrain $
6  created at: Thu Aug 26 14:39:48 JST 1993
7 
8  Copyright (C) 1993-2007 Yukihiro Matsumoto
9 
10 **********************************************************************/
11 
12 #include "ruby/ruby.h"
13 
15 
16 static ID cmp;
17 
18 void
20 {
21  const char *classname;
22 
23  if (SPECIAL_CONST_P(y)) {
24  y = rb_inspect(y);
25  classname = StringValuePtr(y);
26  }
27  else {
28  classname = rb_obj_classname(y);
29  }
30  rb_raise(rb_eArgError, "comparison of %s with %s failed",
31  rb_obj_classname(x), classname);
32 }
33 
34 static VALUE
35 invcmp_recursive(VALUE x, VALUE y, int recursive)
36 {
37  if (recursive) return Qnil;
38  return rb_check_funcall(y, cmp, 1, &x);
39 }
40 
41 VALUE
43 {
45  if (invcmp == Qundef || NIL_P(invcmp)) {
46  return Qnil;
47  }
48  else {
49  int result = -rb_cmpint(invcmp, x, y);
50  return INT2FIX(result);
51  }
52 }
53 
54 static VALUE
56 {
57  VALUE c = rb_funcall(a[0], cmp, 1, a[1]);
58 
59  if (NIL_P(c)) return Qfalse;
60  if (rb_cmpint(c, a[0], a[1]) == 0) return Qtrue;
61  return Qfalse;
62 }
63 
64 static VALUE
66 {
67  return Qfalse;
68 }
69 
70 /*
71  * call-seq:
72  * obj == other -> true or false
73  *
74  * Compares two objects based on the receiver's <code><=></code>
75  * method, returning true if it returns 0. Also returns true if
76  * _obj_ and _other_ are the same object.
77  *
78  * Even if _obj_ <=> _other_ raised an exception, the exception
79  * is ignoread and returns false.
80  */
81 
82 static VALUE
84 {
85  VALUE a[2];
86 
87  if (x == y) return Qtrue;
88 
89  a[0] = x; a[1] = y;
90  return rb_rescue(cmp_eq, (VALUE)a, cmp_failed, 0);
91 }
92 
93 /*
94  * call-seq:
95  * obj > other -> true or false
96  *
97  * Compares two objects based on the receiver's <code><=></code>
98  * method, returning true if it returns 1.
99  */
100 
101 static VALUE
103 {
104  VALUE c = rb_funcall(x, cmp, 1, y);
105 
106  if (rb_cmpint(c, x, y) > 0) return Qtrue;
107  return Qfalse;
108 }
109 
110 /*
111  * call-seq:
112  * obj >= other -> true or false
113  *
114  * Compares two objects based on the receiver's <code><=></code>
115  * method, returning true if it returns 0 or 1.
116  */
117 
118 static VALUE
120 {
121  VALUE c = rb_funcall(x, cmp, 1, y);
122 
123  if (rb_cmpint(c, x, y) >= 0) return Qtrue;
124  return Qfalse;
125 }
126 
127 /*
128  * call-seq:
129  * obj < other -> true or false
130  *
131  * Compares two objects based on the receiver's <code><=></code>
132  * method, returning true if it returns -1.
133  */
134 
135 static VALUE
137 {
138  VALUE c = rb_funcall(x, cmp, 1, y);
139 
140  if (rb_cmpint(c, x, y) < 0) return Qtrue;
141  return Qfalse;
142 }
143 
144 /*
145  * call-seq:
146  * obj <= other -> true or false
147  *
148  * Compares two objects based on the receiver's <code><=></code>
149  * method, returning true if it returns -1 or 0.
150  */
151 
152 static VALUE
154 {
155  VALUE c = rb_funcall(x, cmp, 1, y);
156 
157  if (rb_cmpint(c, x, y) <= 0) return Qtrue;
158  return Qfalse;
159 }
160 
161 /*
162  * call-seq:
163  * obj.between?(min, max) -> true or false
164  *
165  * Returns <code>false</code> if <i>obj</i> <code><=></code>
166  * <i>min</i> is less than zero or if <i>anObject</i> <code><=></code>
167  * <i>max</i> is greater than zero, <code>true</code> otherwise.
168  *
169  * 3.between?(1, 5) #=> true
170  * 6.between?(1, 5) #=> false
171  * 'cat'.between?('ant', 'dog') #=> true
172  * 'gnu'.between?('ant', 'dog') #=> false
173  *
174  */
175 
176 static VALUE
178 {
179  if (RTEST(cmp_lt(x, min))) return Qfalse;
180  if (RTEST(cmp_gt(x, max))) return Qfalse;
181  return Qtrue;
182 }
183 
184 /*
185  * The <code>Comparable</code> mixin is used by classes whose objects
186  * may be ordered. The class must define the <code><=></code> operator,
187  * which compares the receiver against another object, returning -1, 0,
188  * or +1 depending on whether the receiver is less than, equal to, or
189  * greater than the other object. If the other object is not comparable
190  * then the <code><=></code> operator should return nil.
191  * <code>Comparable</code> uses
192  * <code><=></code> to implement the conventional comparison operators
193  * (<code><</code>, <code><=</code>, <code>==</code>, <code>>=</code>,
194  * and <code>></code>) and the method <code>between?</code>.
195  *
196  * class SizeMatters
197  * include Comparable
198  * attr :str
199  * def <=>(anOther)
200  * str.size <=> anOther.str.size
201  * end
202  * def initialize(str)
203  * @str = str
204  * end
205  * def inspect
206  * @str
207  * end
208  * end
209  *
210  * s1 = SizeMatters.new("Z")
211  * s2 = SizeMatters.new("YY")
212  * s3 = SizeMatters.new("XXX")
213  * s4 = SizeMatters.new("WWWW")
214  * s5 = SizeMatters.new("VVVVV")
215  *
216  * s1 < s2 #=> true
217  * s4.between?(s1, s3) #=> false
218  * s4.between?(s3, s5) #=> true
219  * [ s3, s2, s5, s4, s1 ].sort #=> [Z, YY, XXX, WWWW, VVVVV]
220  *
221  */
222 
223 void
225 {
226 #undef rb_intern
227 #define rb_intern(str) rb_intern_const(str)
228 
229  rb_mComparable = rb_define_module("Comparable");
236 
237  cmp = rb_intern("<=>");
238 }
static VALUE classname(VALUE klass, int *permanent)
Returns +classpath+ of klass, if it is named, or +nil+ for anonymous +class+/+module+.
Definition: variable.c:160
static VALUE cmp_gt(VALUE x, VALUE y)
Definition: compar.c:102
void Init_Comparable(void)
Definition: compar.c:224
static VALUE cmp_eq(VALUE *a)
Definition: compar.c:55
static VALUE cmp_le(VALUE x, VALUE y)
Definition: compar.c:153
const char * rb_obj_classname(VALUE)
Definition: variable.c:391
static int max(int a, int b)
Definition: strftime.c:141
static VALUE invcmp_recursive(VALUE x, VALUE y, int recursive)
Definition: compar.c:35
Real * a
Definition: bigdecimal.c:1182
NIL_P(eventloop_thread)
Definition: tcltklib.c:4068
static VALUE cmp_equal(VALUE x, VALUE y)
Definition: compar.c:83
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:774
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1780
return Qtrue
Definition: tcltklib.c:9610
int rb_cmpint(VALUE val, VALUE a, VALUE b)
Definition: bignum.c:97
VALUE rb_rescue(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*r_proc)(ANYARGS), VALUE data2)
Definition: eval.c:763
VALUE rb_mComparable
Definition: compar.c:14
return Qfalse
Definition: tcltklib.c:6779
#define Qnil
Definition: tcltklib.c:1896
#define StringValuePtr(v)
unsigned long ID
Definition: ripper.y:105
#define INT2FIX(i)
static VALUE cmp_between(VALUE x, VALUE min, VALUE max)
Definition: compar.c:177
VALUE rb_check_funcall(VALUE, ID, int, VALUE *)
Definition: vm_eval.c:408
#define RTEST(v)
q result
Definition: tcltklib.c:7070
static VALUE cmp_ge(VALUE x, VALUE y)
Definition: compar.c:119
static int min(int a, int b)
Definition: strftime.c:131
static VALUE cmp_failed(void)
Definition: compar.c:65
VpDivd * c
Definition: bigdecimal.c:1205
static VALUE cmp_lt(VALUE x, VALUE y)
Definition: compar.c:136
#define Qundef
VALUE rb_exec_recursive(VALUE(*)(VALUE, VALUE, int), VALUE, VALUE)
Definition: thread.c:4857
unsigned long VALUE
Definition: ripper.y:104
#define SPECIAL_CONST_P(x)
VALUE rb_define_module(const char *name)
Definition: class.c:617
#define rb_intern(str)
VALUE rb_invcmp(VALUE x, VALUE y)
Definition: compar.c:42
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1340
VALUE rb_eArgError
Definition: error.c:512
static ID cmp
Definition: compar.c:16
void rb_cmperr(VALUE x, VALUE y)
Definition: compar.c:19
VALUE rb_inspect(VALUE)
Definition: object.c:402