001: /***** BEGIN LICENSE BLOCK *****
002: * Version: CPL 1.0/GPL 2.0/LGPL 2.1
003: *
004: * The contents of this file are subject to the Common Public
005: * License Version 1.0 (the "License"); you may not use this file
006: * except in compliance with the License. You may obtain a copy of
007: * the License at http://www.eclipse.org/legal/cpl-v10.html
008: *
009: * Software distributed under the License is distributed on an "AS
010: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
011: * implied. See the License for the specific language governing
012: * rights and limitations under the License.
013: *
014: * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
015: * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
016: * Copyright (C) 2002 Anders Bengtsson <ndrsbngtssn@yahoo.se>
017: * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
018: * Copyright (C) 2002-2004 Thomas E Enebo <enebo@acm.org>
019: * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
020: * Copyright (C) 2005 Charles O Nutter <headius@headius.com>
021: *
022: * Alternatively, the contents of this file may be used under the terms of
023: * either of the GNU General Public License Version 2 or later (the "GPL"),
024: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
025: * in which case the provisions of the GPL or the LGPL are applicable instead
026: * of those above. If you wish to allow use of your version of this file only
027: * under the terms of either the GPL or the LGPL, and not to allow others to
028: * use your version of this file under the terms of the CPL, indicate your
029: * decision by deleting the provisions above and replace them with the notice
030: * and other provisions required by the GPL or the LGPL. If you do not delete
031: * the provisions above, a recipient may use your version of this file under
032: * the terms of any one of the CPL, the GPL or the LGPL.
033: ***** END LICENSE BLOCK *****/package org.jruby;
034:
035: import org.jruby.runtime.Block;
036: import org.jruby.runtime.CallbackFactory;
037: import org.jruby.runtime.MethodIndex;
038: import org.jruby.runtime.ObjectAllocator;
039: import org.jruby.runtime.ThreadContext;
040: import org.jruby.runtime.builtin.IRubyObject;
041:
042: /** Implementation of the Integer class.
043: *
044: * @author jpetersen
045: */
046: public abstract class RubyInteger extends RubyNumeric {
047:
048: public static RubyClass createIntegerClass(Ruby runtime) {
049: RubyClass integer = runtime.defineClass("Integer", runtime
050: .getClass("Numeric"),
051: ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
052: CallbackFactory callbackFactory = runtime
053: .callbackFactory(RubyInteger.class);
054: integer.getSingletonClass().undefineMethod("allocate");
055: integer.getSingletonClass().undefineMethod("new");
056:
057: integer.defineFastMethod("integer?", callbackFactory
058: .getFastMethod("int_p"));
059: integer.defineMethod("upto", callbackFactory.getMethod("upto",
060: RubyKernel.IRUBY_OBJECT));
061: integer.defineMethod("downto", callbackFactory.getMethod(
062: "downto", RubyKernel.IRUBY_OBJECT));
063: integer.defineMethod("times", callbackFactory
064: .getMethod("times"));
065:
066: integer.includeModule(runtime.getModule("Precision"));
067:
068: integer.defineFastMethod("succ", callbackFactory
069: .getFastMethod("succ"));
070: integer.defineFastMethod("next", callbackFactory
071: .getFastMethod("succ"));
072: integer.defineFastMethod("chr", callbackFactory
073: .getFastMethod("chr"));
074: integer.defineFastMethod("to_i", callbackFactory
075: .getFastMethod("to_i"));
076: integer.defineFastMethod("to_int", callbackFactory
077: .getFastMethod("to_i"));
078: integer.defineFastMethod("floor", callbackFactory
079: .getFastMethod("to_i"));
080: integer.defineFastMethod("ceil", callbackFactory
081: .getFastMethod("to_i"));
082: integer.defineFastMethod("round", callbackFactory
083: .getFastMethod("to_i"));
084: integer.defineFastMethod("truncate", callbackFactory
085: .getFastMethod("to_i"));
086:
087: integer.getMetaClass().defineFastMethod(
088: "induced_from",
089: callbackFactory.getFastSingletonMethod("induced_from",
090: RubyKernel.IRUBY_OBJECT));
091: return integer;
092: }
093:
094: public RubyInteger(Ruby runtime, RubyClass rubyClass) {
095: super (runtime, rubyClass);
096: }
097:
098: public RubyInteger convertToInteger() {
099: return this ;
100: }
101:
102: // conversion
103: protected RubyFloat toFloat() {
104: return RubyFloat.newFloat(getRuntime(), getDoubleValue());
105: }
106:
107: /* ================
108: * Instance Methods
109: * ================
110: */
111:
112: /** int_int_p
113: *
114: */
115: public IRubyObject int_p() {
116: return getRuntime().getTrue();
117: }
118:
119: /** int_upto
120: *
121: */
122: public IRubyObject upto(IRubyObject to, Block block) {
123: Ruby runtime = getRuntime();
124: ThreadContext context = runtime.getCurrentContext();
125:
126: if (this instanceof RubyFixnum && to instanceof RubyFixnum) {
127:
128: RubyFixnum toFixnum = (RubyFixnum) to;
129: long toValue = toFixnum.getLongValue();
130: long fromValue = getLongValue();
131: for (long i = fromValue; i <= toValue; i++) {
132: block.yield(context, RubyFixnum.newFixnum(runtime, i));
133: }
134: } else {
135: RubyNumeric i = this ;
136:
137: while (true) {
138: if (i.callMethod(context, MethodIndex.OP_GT, ">", to)
139: .isTrue()) {
140: break;
141: }
142: block.yield(context, i);
143: i = (RubyNumeric) i.callMethod(context,
144: MethodIndex.OP_PLUS, "+", RubyFixnum
145: .one(runtime));
146: }
147: }
148: return this ;
149: }
150:
151: /** int_downto
152: *
153: */
154: // TODO: Make callCoerced work in block context...then fix downto, step, and upto.
155: public IRubyObject downto(IRubyObject to, Block block) {
156: ThreadContext context = getRuntime().getCurrentContext();
157:
158: if (this instanceof RubyFixnum && to instanceof RubyFixnum) {
159: RubyFixnum toFixnum = (RubyFixnum) to;
160: long toValue = toFixnum.getLongValue();
161: for (long i = getLongValue(); i >= toValue; i--) {
162: block.yield(context, RubyFixnum.newFixnum(getRuntime(),
163: i));
164: }
165: } else {
166: RubyNumeric i = this ;
167:
168: while (true) {
169: if (i.callMethod(context, MethodIndex.OP_LT, "<", to)
170: .isTrue()) {
171: break;
172: }
173: block.yield(context, i);
174: i = (RubyNumeric) i.callMethod(context,
175: MethodIndex.OP_MINUS, "-", RubyFixnum
176: .one(getRuntime()));
177: }
178: }
179: return this ;
180: }
181:
182: public IRubyObject times(Block block) {
183: ThreadContext context = getRuntime().getCurrentContext();
184:
185: if (this instanceof RubyFixnum) {
186:
187: long value = getLongValue();
188: for (long i = 0; i < value; i++) {
189: block.yield(context, RubyFixnum.newFixnum(getRuntime(),
190: i));
191: }
192: } else {
193: RubyNumeric i = RubyFixnum.zero(getRuntime());
194: while (true) {
195: if (!i
196: .callMethod(context, MethodIndex.OP_LT, "<",
197: this ).isTrue()) {
198: break;
199: }
200: block.yield(context, i);
201: i = (RubyNumeric) i.callMethod(context,
202: MethodIndex.OP_PLUS, "+", RubyFixnum
203: .one(getRuntime()));
204: }
205: }
206:
207: return this ;
208: }
209:
210: /** int_succ
211: *
212: */
213: public IRubyObject succ() {
214: if (this instanceof RubyFixnum) {
215: return RubyFixnum.newFixnum(getRuntime(),
216: getLongValue() + 1L);
217: } else {
218: return callMethod(getRuntime().getCurrentContext(),
219: MethodIndex.OP_PLUS, "+", RubyFixnum
220: .one(getRuntime()));
221: }
222: }
223:
224: /** int_chr
225: *
226: */
227: public RubyString chr() {
228: if (getLongValue() < 0 || getLongValue() > 0xff) {
229: throw getRuntime().newRangeError(
230: this .toString() + " out of char range");
231: }
232: return getRuntime().newString(
233: new String(new char[] { (char) getLongValue() }));
234: }
235:
236: /** int_to_i
237: *
238: */
239: public RubyInteger to_i() {
240: return this ;
241: }
242:
243: /* ================
244: * Singleton Methods
245: * ================
246: */
247:
248: /** rb_int_induced_from
249: *
250: */
251: public static IRubyObject induced_from(IRubyObject recv,
252: IRubyObject other) {
253: if (other instanceof RubyFixnum || other instanceof RubyBignum) {
254: return other;
255: } else if (other instanceof RubyFloat) {
256: return other.callMethod(recv.getRuntime()
257: .getCurrentContext(), MethodIndex.TO_I, "to_i");
258: } else {
259: throw recv.getRuntime().newTypeError(
260: "failed to convert "
261: + other.getMetaClass().getName()
262: + " into Integer");
263: }
264: }
265: }
|