Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 9cb25df886a6
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2647bef7eb1f
Choose a head ref
  • 4 commits
  • 5 files changed
  • 1 contributor

Commits on Jan 23, 2018

  1. Copy the full SHA
    a7e371c View commit details
  2. Copy the full SHA
    c05c93e View commit details
  3. Copy the full SHA
    ff1aae0 View commit details
  4. Copy the full SHA
    2647bef View commit details
158 changes: 83 additions & 75 deletions core/src/main/java/org/jruby/RubyComplex.java
Original file line number Diff line number Diff line change
@@ -67,18 +67,17 @@
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.callsite.RespondToCallSite;
import org.jruby.util.ByteList;
import org.jruby.util.Numeric;
import org.jruby.util.TypeConverter;

import static org.jruby.runtime.Helpers.invokedynamic;
import static org.jruby.runtime.invokedynamic.MethodNames.HASH;
import static org.jruby.util.Numeric.safe_mul;

/**
* 1.9 complex.c as of revision: 20011
* complex.c as of revision: 20011
*/

@JRubyClass(name = "Complex", parent = "Numeric")
public class RubyComplex extends RubyNumeric {

@@ -166,34 +165,37 @@ static IRubyObject newComplexPolar(ThreadContext context, IRubyObject x, IRubyOb
/** f_complex_new1
*
*/
static IRubyObject newComplex(ThreadContext context, RubyClass clazz, IRubyObject x) {
static RubyNumeric newComplex(ThreadContext context, RubyClass clazz, IRubyObject x) {
return newComplex(context, clazz, x, RubyFixnum.zero(context.runtime));
}

/** f_complex_new2
*
*/
static IRubyObject newComplex(ThreadContext context, RubyClass clazz, IRubyObject x, IRubyObject y) {
static RubyNumeric newComplex(ThreadContext context, RubyClass clazz, IRubyObject x, IRubyObject y) {
assert !(x instanceof RubyComplex);
return canonicalizeInternal(context, clazz, x, y);
}

/** f_complex_new_bang2
*
*/
static RubyComplex newComplexBang(ThreadContext context, RubyClass clazz, IRubyObject x, IRubyObject y) {
// FIXME: what should these really be? Numeric? assert x instanceof RubyComplex && y instanceof RubyComplex;
static RubyComplex newComplexBang(ThreadContext context, RubyClass clazz, RubyNumeric x, RubyNumeric y) {
return new RubyComplex(context.runtime, clazz, x, y);
}

/** f_complex_new_bang1
*
*/
public static RubyComplex newComplexBang(ThreadContext context, RubyClass clazz, IRubyObject x) {
// FIXME: what should this really be? assert x instanceof RubyComplex;
static RubyComplex newComplexBang(ThreadContext context, RubyClass clazz, RubyNumeric x) {
return newComplexBang(context, clazz, x, RubyFixnum.zero(context.runtime));
}

@Deprecated
public static RubyComplex newComplexBang(ThreadContext context, RubyClass clazz, IRubyObject x) {
return newComplexBang(context, clazz, (RubyNumeric) x);
}

private IRubyObject real;
private IRubyObject image;

@@ -254,12 +256,12 @@ private static IRubyObject m_sqrt(ThreadContext context, IRubyObject x) {
*
*/
@Deprecated
public static IRubyObject newInstanceBang(ThreadContext context, IRubyObject recv, IRubyObject[]args) {
public static IRubyObject newInstanceBang(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
switch (args.length) {
case 1: return newInstanceBang(context, recv, args[0]);
case 2: return newInstanceBang(context, recv, args[0], args[1]);
case 1: return newInstanceBang(context, recv, args[0]);
case 2: return newInstanceBang(context, recv, args[0], args[1]);
}
Arity.raiseArgumentError(context.runtime, args.length, 1, 1);
Arity.raiseArgumentError(context.runtime, args.length, 1, 2);
return null;
}

@@ -336,16 +338,16 @@ private static RubyNumeric canonicalizeInternal(ThreadContext context, RubyClass
*
*/
@Deprecated
public static IRubyObject newInstance(ThreadContext context, IRubyObject recv, IRubyObject[]args) {
public static IRubyObject newInstance(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
switch (args.length) {
case 1: return newInstance(context, recv, args[0]);
case 2: return newInstance(context, recv, args[0], args[1]);
case 1: return newInstance(context, recv, args[0]);
case 2: return newInstance(context, recv, args[0], args[1]);
}
Arity.raiseArgumentError(context.runtime, args.length, 1, 1);
Arity.raiseArgumentError(context.runtime, args.length, 1, 2);
return null;
}

// @JRubyMethod(name = "new", meta = true, visibility = Visibility.PRIVATE)
@Deprecated // @JRubyMethod(name = "new", meta = true, visibility = Visibility.PRIVATE)
public static IRubyObject newInstanceNew(ThreadContext context, IRubyObject recv, IRubyObject real) {
return newInstance(context, recv, real);
}
@@ -356,7 +358,7 @@ public static IRubyObject newInstance(ThreadContext context, IRubyObject recv, I
return canonicalizeInternal(context, (RubyClass) recv, real, RubyFixnum.zero(context.runtime));
}

// @JRubyMethod(name = "new", meta = true, visibility = Visibility.PRIVATE)
@Deprecated // @JRubyMethod(name = "new", meta = true, visibility = Visibility.PRIVATE)
public static IRubyObject newInstanceNew(ThreadContext context, IRubyObject recv, IRubyObject real, IRubyObject image) {
return newInstance(context, recv, real, image);
}
@@ -378,18 +380,11 @@ private static IRubyObject f_complex_polar(ThreadContext context, RubyClass claz
f_mul(context, x, m_sin(context, y)));
}

/** nucomp_s_polar
*
*/
public static IRubyObject polar(ThreadContext context, IRubyObject clazz, IRubyObject abs, IRubyObject arg) {
return polar19(context, clazz, new IRubyObject[]{abs, arg});
}

/** nucomp_s_polar
*
*/
@JRubyMethod(name = "polar", meta = true, required = 1, optional = 1)
public static IRubyObject polar19(ThreadContext context, IRubyObject clazz, IRubyObject[] args) {
public static IRubyObject polar(ThreadContext context, IRubyObject clazz, IRubyObject... args) {
IRubyObject abs = args[0];
IRubyObject arg;
if (args.length < 2) {
@@ -402,6 +397,11 @@ public static IRubyObject polar19(ThreadContext context, IRubyObject clazz, IRub
return f_complex_polar(context, (RubyClass) clazz, abs, arg);
}

@Deprecated
public static IRubyObject polar19(ThreadContext context, IRubyObject clazz, IRubyObject[] args) {
return polar(context, clazz, args);
}

/** rb_Complex1
*
*/
@@ -431,65 +431,60 @@ public static IRubyObject convert(ThreadContext context, IRubyObject clazz, IRub
*/
@JRubyMethod(name = "convert", meta = true, visibility = Visibility.PRIVATE)
public static IRubyObject convert(ThreadContext context, IRubyObject recv, IRubyObject arg) {
return convertCommon(context, recv, arg, context.nil, true);
}

private static boolean responds_to_to_c(ThreadContext context, IRubyObject obj) {
return respond_to_to_c.respondsTo(context, obj, obj);
return convertCommon(context, recv, arg, null);
}

// TODO: wasn't sure whether to put this on NumericSites, here for now - should move
static final RespondToCallSite respond_to_to_c = new RespondToCallSite("to_c");

/** nucomp_s_convert
*
*/
@JRubyMethod(name = "convert", meta = true, visibility = Visibility.PRIVATE)
public static IRubyObject convert(ThreadContext context, IRubyObject recv, IRubyObject a1, IRubyObject a2) {
return convertCommon(context, recv, a1, a2, false);
return convertCommon(context, recv, a1, a2);
}

private static IRubyObject convertCommon(ThreadContext context, IRubyObject recv,
IRubyObject a1, IRubyObject a2, final boolean singleArg) {

// MRI: nucomp_s_convert
private static IRubyObject convertCommon(ThreadContext context, IRubyObject recv, IRubyObject a1, IRubyObject a2) {
final boolean singleArg = a2 == null;

if (a1 == context.nil || a2 == context.nil) {
throw context.runtime.newTypeError("can't convert nil into Complex");
}

if (a1 instanceof RubyString) a1 = str_to_c_strict(context, (RubyString) a1);
if (a2 instanceof RubyString) a2 = str_to_c_strict(context, (RubyString) a2);

if (a1 instanceof RubyComplex) {
RubyComplex a1c = (RubyComplex) a1;
if (k_exact_p(a1c.image) && f_zero_p(context, a1c.image)) {
a1 = a1c.real;
}
if (k_exact_p(a1c.image) && f_zero_p(context, a1c.image)) a1 = a1c.real;
}

if (a2 instanceof RubyComplex) {
RubyComplex a2c = (RubyComplex) a2;
if (k_exact_p(a2c.image) && f_zero_p(context, a2c.image)) {
a2 = a2c.real;
}
if (k_exact_p(a2c.image) && f_zero_p(context, a2c.image)) a2 = a2c.real;
}

if (a1 instanceof RubyComplex) {
if (a2 == context.nil || (k_exact_p(a2) && f_zero_p(context, a2))) return a1;
if (singleArg || (k_exact_p(a2) && f_zero_p(context, a2))) return a1;
}

if (a2 == context.nil) {
if (singleArg) {
if (a1 instanceof RubyNumeric) {
if (!f_real_p(context, (RubyNumeric) a1)) return a1;
if (!f_real_p(context, a1)) return a1;
}
else if (singleArg && a1 != context.nil && responds_to_to_c(context, a1)) {
return a1.callMethod(context, "to_c");
else { // if (!k_numeric_p(a1))
return TypeConverter.convertToType(context, a1, context.runtime.getComplex(), sites(context).to_c_checked);
}
return newInstance(context, recv, a1);
} else {
if (a1 instanceof RubyNumeric && a2 instanceof RubyNumeric &&
(!f_real_p(context, (RubyNumeric) a1) || !f_real_p(context, (RubyNumeric) a2))) {
Ruby runtime = context.runtime;
return f_add(context, a1,
f_mul(context, a2, newComplexBang(context, runtime.getComplex(),
RubyFixnum.zero(runtime), RubyFixnum.one(runtime))));
}
return newInstance(context, recv, a1, a2);
}

if (a1 instanceof RubyNumeric && a2 instanceof RubyNumeric &&
(!f_real_p(context, a1) || !f_real_p(context, a2))) {
Ruby runtime = context.runtime;
return f_add(context, a1,
f_mul(context, a2, newComplexBang(context, runtime.getComplex(),
RubyFixnum.zero(runtime), RubyFixnum.one(runtime))));
}
return newInstance(context, recv, a1, a2);
}

/** nucomp_real
@@ -499,7 +494,7 @@ else if (singleArg && a1 != context.nil && responds_to_to_c(context, a1)) {
public IRubyObject real() {
return real;
}

/** nucomp_image
*
*/
@@ -584,22 +579,19 @@ public IRubyObject op_div(ThreadContext context, IRubyObject other) {
RubyComplex otherComplex = (RubyComplex)other;
if (real instanceof RubyFloat || image instanceof RubyFloat ||
otherComplex.real instanceof RubyFloat || otherComplex.image instanceof RubyFloat) {
IRubyObject magn = RubyMath.hypot(context, this, otherComplex.real, otherComplex.image);
IRubyObject tmp = newComplexBang(context, getMetaClass(),
f_quo(context, otherComplex.real, magn),
f_quo(context, otherComplex.image, magn));
RubyFloat magn = RubyMath.hypot(context, this, otherComplex.real, otherComplex.image);
RubyComplex tmp = newComplexBang(context, getMetaClass(),
(RubyNumeric) f_quo(context, otherComplex.real, magn),
(RubyNumeric) f_quo(context, otherComplex.image, magn));
return f_quo(context, f_mul(context, this, f_conjugate(context, tmp)), magn);
}
return f_quo(context, f_mul(context, this, f_conjugate(context, other)), f_abs2(context, other));
} else if (other instanceof RubyNumeric) {
if (f_real_p(context, (RubyNumeric) other)) {
return newComplex(context, getMetaClass(),
f_quo(context, real, other),
f_quo(context, image, other));
} else {
RubyArray coercedOther = doCoerce(context, other, true);
return RubyRational.newInstance(context, context.runtime.getRational(), coercedOther.first(), coercedOther.last());
return newComplex(context, getMetaClass(), f_quo(context, real, other), f_quo(context, image, other));
}
RubyArray coercedOther = doCoerce(context, other, true);
return RubyRational.newInstance(context, context.runtime.getRational(), coercedOther.eltInternal(0), coercedOther.eltInternal(1));
}
return coerceBin(context, sites(context).op_quo, other);
}
@@ -705,7 +697,7 @@ public IRubyObject op_equal(ThreadContext context, IRubyObject other) {
@JRubyMethod(name = "coerce")
public IRubyObject coerce(ThreadContext context, IRubyObject other) {
if (other instanceof RubyNumeric && f_real_p(context, (RubyNumeric) other)) {
return context.runtime.newArray(newComplexBang(context, getMetaClass(), other), this);
return context.runtime.newArray(newComplexBang(context, getMetaClass(), (RubyNumeric) other), this);
}
if (other instanceof RubyComplex) {
return context.runtime.newArray(other, this);
@@ -794,15 +786,15 @@ public IRubyObject complex_p(ThreadContext context) {
*/
// @JRubyMethod(name = "exact?")
public IRubyObject exact_p(ThreadContext context) {
return (f_exact_p(context, real).isTrue() && f_exact_p(context, image).isTrue()) ? context.runtime.getTrue() : context.runtime.getFalse();
return (f_exact_p(context, real) && f_exact_p(context, image)) ? context.tru : context.fals;
}

/** nucomp_exact_p
*
*/
// @JRubyMethod(name = "inexact?")
public IRubyObject inexact_p(ThreadContext context) {
return exact_p(context).isTrue() ? context.runtime.getFalse() : context.runtime.getTrue();
return exact_p(context) == context.tru ? context.fals : context.tru;
}

/** nucomp_denominator
@@ -837,21 +829,37 @@ public IRubyObject hash(ThreadContext context) {
return f_xor(context, invokedynamic(context, real, HASH), invokedynamic(context, image, HASH));
}

@Override
public int hashCode() {
final IRubyObject hash = hash(getRuntime().getCurrentContext());
if (hash instanceof RubyFixnum) return (int) RubyNumeric.fix2long(hash);
return nonFixnumHashCode(hash);
}

/** nucomp_eql_p
*
*/
@JRubyMethod(name = "eql?")
@Override
public IRubyObject eql_p(ThreadContext context, IRubyObject other) {
return context.runtime.newBoolean(equals(context, other));
}

private boolean equals(ThreadContext context, Object other) {
if (other instanceof RubyComplex) {
RubyComplex otherComplex = (RubyComplex)other;
if (real.getMetaClass() == otherComplex.real.getMetaClass() &&
image.getMetaClass() == otherComplex.image.getMetaClass() &&
f_equal(context, this, otherComplex).isTrue()) {
return context.runtime.getTrue();
return true;
}
}
return context.runtime.getFalse();
return false;
}

@Override
public boolean equals(Object other) {
return equals(getRuntime().getCurrentContext(), other);
}

/** f_signbit
Original file line number Diff line number Diff line change
@@ -1867,7 +1867,7 @@ private String infinityString() {
return infinitySign == -1 ? "-Infinity" : "Infinity";
}

private boolean is_even(IRubyObject x) {
private static boolean is_even(IRubyObject x) {
if (x instanceof RubyFixnum) return RubyNumeric.fix2long((RubyFixnum) x) % 2 == 0;
if (x instanceof RubyBignum) return RubyBignum.big2long((RubyBignum) x) % 2 == 0;

2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/runtime/JavaSites.java
Original file line number Diff line number Diff line change
@@ -311,7 +311,6 @@ public static class IOSites {
public final CallSite read = new FunctionalCachingCallSite("read");
public final CallSite to_f = new FunctionalCachingCallSite("to_f");
public final CallSite new_ = new FunctionalCachingCallSite("new");
public final RespondToCallSite respond_to_to_int = new RespondToCallSite("to_int");
public final RespondToCallSite respond_to_to_io = new RespondToCallSite("to_io");
public final RespondToCallSite respond_to_to_hash = new RespondToCallSite("to_hash");
}
@@ -369,6 +368,7 @@ public static class ComplexSites {
public final CallSite op_minus = new FunctionalCachingCallSite("-");
public final CallSite finite = new FunctionalCachingCallSite("finite?");
public final CallSite infinite = new FunctionalCachingCallSite("infinite?");
public final CheckedSites to_c_checked = new CheckedSites("to_c");
}

public static class RationalSites {
37 changes: 33 additions & 4 deletions core/src/main/java/org/jruby/util/Numeric.java
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@
import org.jcodings.specific.ASCIIEncoding;
import org.jruby.Ruby;
import org.jruby.RubyBignum;
import org.jruby.RubyComplex;
import org.jruby.RubyFixnum;
import org.jruby.RubyFloat;
import org.jruby.RubyInteger;
@@ -246,9 +247,9 @@ public static IRubyObject f_denominator(ThreadContext context, IRubyObject x) {

/** f_exact_p
*
*/
public static IRubyObject f_exact_p(ThreadContext context, IRubyObject x) {
return sites(context).exact.call(context, x, x);
*/ // NOTE: not (really) used
public static boolean f_exact_p(ThreadContext context, IRubyObject x) {
return sites(context).exact.call(context, x, x).isTrue();
}

/** f_numerator
@@ -269,6 +270,18 @@ public static IRubyObject f_polar(ThreadContext context, IRubyObject x) {
*
*/
public static boolean f_real_p(ThreadContext context, IRubyObject x) {
// NOTE: can not use instanceof RubyNumeric + ((RubyNumeric) x).isReal()
// since Numeric is not a terminal type -> might get sub-classed by user
switch (x.getMetaClass().getClassIndex()) {
case FLOAT:
case FIXNUM:
case BIGNUM:
case RATIONAL:
return ((RubyNumeric) x).isReal(); // true
case COMPLEX:
return ((RubyComplex) x).isReal(); // false

}
return sites(context).real.call(context, x, x).isTrue();
}

@@ -286,6 +299,10 @@ public static IRubyObject f_divmod(ThreadContext context, IRubyObject x, IRubyOb
return sites(context).divmod.call(context, x, x, y);
}

public static IRubyObject f_divmod(ThreadContext context, RubyInteger x, IRubyObject y) {
return x.divmod(context, y);
}

/** f_floor
*
*/
@@ -307,6 +324,10 @@ public static IRubyObject f_negate(ThreadContext context, IRubyObject x) {
return sites(context).op_uminus.call(context, x, x);
}

public static RubyInteger f_negate(ThreadContext context, RubyInteger x) {
return x.negate();
}

/** f_to_f
*
*/
@@ -327,7 +348,11 @@ public static IRubyObject f_to_i(ThreadContext context, IRubyObject x) {
public static IRubyObject f_to_r(ThreadContext context, IRubyObject x) {
return sites(context).to_r.call(context, x, x);
}


public static RubyNumeric f_to_r(ThreadContext context, RubyInteger x) {
return (RubyNumeric) x.to_r(context);
}

/** f_to_s
*
*/
@@ -389,6 +414,10 @@ public static IRubyObject f_quo(ThreadContext context, IRubyObject x, IRubyObjec
return sites(context).quo.call(context, x, x, y);
}

public static IRubyObject f_quo(ThreadContext context, RubyFloat x, RubyFloat y) {
return x.quo(context, y);
}

/** f_rshift
*
*/
12 changes: 10 additions & 2 deletions spec/ruby/shared/complex/Complex.rb
Original file line number Diff line number Diff line change
@@ -35,7 +35,7 @@
end
end

describe "when passed [Integer]" do
describe "when passed [Integer/Float]" do
it "returns a new Complex number with 0 as the imaginary component" do
# Guard against the Mathn library
conflicts_with :Prime do
@@ -62,7 +62,7 @@
it "needs to be reviewed for spec completeness"
end

describe "when passed an Objectc which responds to #to_c" do
describe "when passed an Object which responds to #to_c" do
it "returns the passed argument" do
obj = Object.new; def obj.to_c; 1i end
Complex(obj).should == Complex(0, 1)
@@ -130,4 +130,12 @@
lambda { Complex.send(@method, 0, :sym) }.should raise_error(TypeError)
end
end

describe "when passed nil" do
it "raises TypeError" do
lambda { Complex(nil) }.should raise_error(TypeError, "can't convert nil into Complex")
lambda { Complex(0, nil) }.should raise_error(TypeError, "can't convert nil into Complex")
lambda { Complex(nil, 0) }.should raise_error(TypeError, "can't convert nil into Complex")
end
end
end