Ruby 2.0.0p353(2013-11-22revision43784)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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