Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
BEGIN LICENSE BLOCK ***** Version: CPL 1.0/GPL 2.0/LGPL 2.1 The contents of this file are subject to the Common Public License Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.eclipse.org/legal/cpl-v10.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Alternatively, the contents of this file may be used under the terms of either of the GNU General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the CPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the CPL, the GPL or the LGPL. END LICENSE BLOCK ***
 
 package org.jruby;
 
 
 import static org.jruby.runtime.Visibility.PRIVATE;
 import static org.jruby.CompatVersion.*;
Implementation of the Random class.
 
 @JRubyClass(name = "Random")
 public class RubyRandom extends RubyObject {
 
     public static class RandomType {
         private final IRubyObject seed;
         private final Random mt;
 
         RandomType(Ruby runtime) {
             this(randomSeed(runtime));
         }
 
         // c: rand_init
         RandomType(IRubyObject vseed) {
             this. = vseed.convertToInteger();
             if ( instanceof RubyFixnum) {
                 long v = Math.abs(RubyNumeric.num2long());
                 if (v == (v & 0xffffffffL)) {
                     this. = new Random((intv);
                 } else {
                     int[] ints = new int[2];
                     ints[0] = (intv;
                     ints[1] = (int) (v >> 32);
                     this. = new Random(ints);
                 }
             } else if ( instanceof RubyBignum) {
                 BigInteger big = ((RubyBignum).getBigIntegerValue();
                 if (big.signum() < 0) {
                     big = big.abs();
                 }
                 byte[] buf = big.toByteArray();
                 int buflen = buf.length;
                 if (buf[0] == 0) {
                     buflen -= 1;
                 }
                 int len = Math.min((buflen + 3) / 4, .);
                 int[] ints = bigEndianToInts(buflen);
                 if (len <= 1) {
                     this. = new Random(ints[0]);
                 } else {
                     this. = new Random(ints);
                 }
             } else {
                 throw vseed.getRuntime().newTypeError(
                         String.format("failed to convert %s into Integer"vseed.getMetaClass()
                                 .getName()));
             }
         }
 
         RandomType(IRubyObject vseedRubyBignum stateint left) {
             this. = vseed.convertToInteger();
             byte[] bytes = state.getBigIntegerValue().toByteArray();
             int[] ints = new int[bytes.length / 4];
             for (int i = 0; i < ints.length; ++i) {
                 ints[i] = getIntBigIntegerBuffer(bytesi);
             }
            this. = new Random(intsleft);
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            } else if (!(obj instanceof RandomType)) {
                return false;
            }
            RandomType rhs = (RandomTypeobj;
            return .op_equal(.getRuntime().getCurrentContext(), rhs.seed).isTrue()
                    && .equals(rhs.mt);
        }
        @Override
        public int hashCode() {
            // Using 17 as the initializer, 37 as the multiplier.
            return (629 + .hashCode()) * 37 + .hashCode();
        }
        RandomType(RandomType orig) {
            this. = orig.seed;
            this. = new Random(orig.mt);
        }
        int genrandInt32() {
            return .genrandInt32();
        }
        double genrandReal() {
            return .genrandReal();
        }
        double genrandReal2() {
            return .genrandReal2();
        }
        IRubyObject getSeed() {
            return ;
        }
        RubyBignum getState() {
            int[] ints = .getState();
            byte[] bytes = new byte[ints.length * 4];
            for (int idx = 0; idx < ints.length; ++idx) {
                setIntBigIntegerBuffer(bytesidxints[idx]);
            }
            return RubyBignum.newBignum(.getRuntime(), new BigInteger(bytes));
        }
        int getLeft() {
            return .getLeft();
        }
        // big endian of bytes to reversed ints
        private int[] bigEndianToInts(byte[] bufint initKeyLen) {
            int[] initKey = new int[initKeyLen];
            for (int idx = 0; idx < initKey.length; ++idx) {
                initKey[idx] = getIntBigIntegerBuffer(bufidx);
            }
            return initKey;
        }
    }
    static int getIntBigIntegerBuffer(byte[] srcint loc) {
        int v = 0;
        int idx = src.length - loc * 4 - 1;
        if (idx >= 0) {
            v |= (src[idx--] & 0xff);
            if (idx >= 0) {
                v |= (src[idx--] & 0xff) << 8;
                if (idx >= 0) {
                    v |= (src[idx--] & 0xff) << 16;
                    if (idx >= 0) {
                        v |= (src[idx--] & 0xff) << 24;
                    }
                }
            }
        }
        return v;
    }
    static void setIntBigIntegerBuffer(byte[] destint locint value) {
        int idx = dest.length - loc * 4 - 1;
        if (idx >= 0) {
            dest[idx--] = (byte) (value & 0xff);
            if (idx >= 0) {
                dest[idx--] = (byte) ((value >> 8) & 0xff);
                if (idx >= 0) {
                    dest[idx--] = (byte) ((value >> 16) & 0xff);
                    if (idx >= 0) {
                        dest[idx--] = (byte) ((value >> 24) & 0xff);
                    }
                }
            }
        }
    }
    private static final int DEFAULT_SEED_CNT = 4;
    // c: random_seed
    public static RubyBignum randomSeed(Ruby runtime) {
        byte[] seed = new byte[ * 4];
        runtime.getRandom().nextBytes(seed);
        return RubyBignum.newBignum(runtime, (new BigInteger(seed)).abs());
    }
    public static RubyClass createRandomClass(Ruby runtime) {
        RubyClass randomClass = runtime
                .defineClass("Random"runtime.getObject(), );
        randomClass.defineAnnotatedMethods(RubyRandom.class);
        RubyRandom defaultRand = new RubyRandom(runtimerandomClass);
        defaultRand.random = new RandomType(randomSeed(runtime));
        randomClass.setConstant("DEFAULT"defaultRand);
        runtime.setDefaultRand(defaultRand.random);
        runtime.setRandomClass(randomClass);
        return randomClass;
    }
    private static ObjectAllocator RANDOM_ALLOCATOR = new ObjectAllocator() {
        public IRubyObject allocate(Ruby runtimeRubyClass klass) {
            return new RubyRandom(runtimeklass);
        }
    };
    private RandomType random = null;
    RubyRandom(Ruby runtimeRubyClass rubyClass) {
        super(runtimerubyClass);
    }
    @JRubyMethod(visibility = , optional = 1, compat = )
    public IRubyObject initialize(ThreadContext contextIRubyObject[] args) {
         = new RandomType((args.length == 0) ? randomSeed(context.runtime) : args[0]);
        return this;
    }
    @JRubyMethod(name = "seed", compat = )
    public IRubyObject seed(ThreadContext context) {
        return .getSeed();
    }
    @JRubyMethod(name = "initialize_copy", required = 1, visibility = )
    @Override
    public IRubyObject initialize_copy(IRubyObject orig) {
        if (!(orig instanceof RubyRandom)) {
            throw getRuntime().newTypeError(
                    String.format("wrong argument type %s (expected %s)"orig.getMetaClass()
                            .getName(), getMetaClass().getName()));
        }
         = new RandomType(((RubyRandomorig).);
        return this;
    }
    @JRubyMethod(name = "rand", meta = true, optional = 1, compat = )
    public static IRubyObject rand(ThreadContext contextIRubyObject recvIRubyObject[] args) {
        return randCommon19(contextrecvargs);
    }
    // c: rb_f_rand for 1.9
    public static IRubyObject randCommon19(ThreadContext contextIRubyObject recv,
            IRubyObject[] args) {
        RandomType random = getDefaultRand(context);
        if (args.length == 0) {
            return randFloat(contextrandom);
        }
        IRubyObject arg = args[0];
        if (arg.isNil()) {
            return randFloat(contextrandom);
        }
        if (arg instanceof RubyRange) {
            return randomRand(contextargrandom);
        }
        RubyInteger max = arg.convertToInteger();
        return randCommon(contextrandommax);
    }
    // c: rb_f_rand for 1.8
    public static IRubyObject randCommon18(ThreadContext contextIRubyObject recv,
            IRubyObject[] args) {
        RandomType random = getDefaultRand(context);
        if (args.length == 0) {
            return randFloat(contextrandom);
        }
        IRubyObject arg = args[0];
        if (arg.isNil()) {
            return randFloat(contextrandom);
        }
        // 1.8 calls rb_Integer()
        RubyInteger max = (RubyInteger) RubyKernel.new_integer(contextrecvarg);
        return randCommon(contextrandommax);
    }
    private static IRubyObject randCommon(ThreadContext contextRandomType randomRubyInteger max) {
        if (max.zero_p(context).isTrue()) {
            return randFloat(contextrandom);
        }
        IRubyObject r = randInt(contextrandommaxfalse);
        if (r.isNil()) {
            return randFloat(contextrandom);
        }
        return r;
    }
    @JRubyMethod(name = "rand", optional = 1, compat = )
    public IRubyObject randObj(ThreadContext contextIRubyObject[] args) {
        if (args.length == 0) {
            return randFloat(context);
        } else {
            return randomRand(contextargs[0], );
        }
    }
    // c: rand_int
    private static IRubyObject randInt(ThreadContext contextRandomType randomRubyInteger vmax,
            boolean restrictive) {
        if (vmax instanceof RubyFixnum) {
            long max = RubyNumeric.fix2long(vmax);
            if (max == 0) {
                return context.nil;
            }
            if (max < 0) {
                if (restrictive) {
                    return context.nil;
                }
                max = -max;
            }
            return randLimitedFixnum(contextrandommax - 1);
        } else {
            BigInteger big = vmax.getBigIntegerValue();
            if (big.equals(.)) {
                return context.nil;
            }
            if (big.signum() < 0) {
                if (restrictive) {
                    return context.nil;
                }
                big = big.abs();
            }
            big = big.subtract(.);
            return randLimitedBignum(contextrandom, RubyBignum.newBignum(context.runtimebig));
        }
    }
    public static RubyFloat randFloat(ThreadContext contextRandomType random) {
        return context.runtime.newFloat(random.genrandReal());
    }
    // c: limited_rand
    // limited_rand gets/returns ulong but we do this in signed long only.
    private static IRubyObject randLimitedFixnum(ThreadContext contextRandomType random,
            long limit) {
        long val;
        if (limit == 0) {
            val = 0;
        } else {
            long mask = makeMask(limit);
            // take care before code cleanup; it might break random sequence compatibility
            retry: while (true) {
                val = 0;
                for (int i = 1; 0 <= i; --i) {
                    if (((mask >>> (i * 32)) & 0xffffffffL) != 0) {
                        val |= (random.genrandInt32() & 0xffffffffL) << (i * 32);
                        val &= mask;
                    }
                    if (limit < val) {
                        continue retry;
                    }
                }
                break;
            }
        }
        return context.runtime.newFixnum(val);
    }
    // c: limited_big_rand
    private static IRubyObject randLimitedBignum(ThreadContext contextRandomType random,
            RubyBignum limit) {
        byte[] buf = limit.getBigIntegerValue().toByteArray();
        byte[] bytes = new byte[buf.length];
        int len = (buf.length + 3) / 4;
        // take care before code cleanup; it might break random sequence compatibility
        retry: while (true) {
            long mask = 0;
            boolean boundary = true;
            for (int idx = len - 1; 0 <= idx; --idx) {
                long lim = getIntBigIntegerBuffer(bufidx) & 0xffffffffL;
                mask = (mask != 0) ? 0xffffffffL : makeMask(lim);
                long rnd;
                if (mask != 0) {
                    rnd = (random.genrandInt32() & 0xffffffffL) & mask;
                    if (boundary) {
                        if (lim < rnd) {
                            continue retry;
                        }
                        if (rnd < lim) {
                            boundary = false;
                        }
                    }
                } else {
                    rnd = 0;
                }
                setIntBigIntegerBuffer(bytesidx, (intrnd);
            }
            break;
        }
        return RubyBignum.newBignum(context.runtimenew BigInteger(bytes));
    }
    private static long makeMask(long x) {
        x = x | x >>> 1;
        x = x | x >>> 2;
        x = x | x >>> 4;
        x = x | x >>> 8;
        x = x | x >>> 16;
        x = x | x >>> 32;
        return x;
    }
    private static RandomType getDefaultRand(ThreadContext context) {
        return context.runtime.getDefaultRand();
    }
    // c: random_rand
    private static IRubyObject randomRand(ThreadContext contextIRubyObject vmaxRandomType random) {
        IRubyObject v = null;
        RangeLike range = null;
        if (vmax.isNil()) {
            v = context.nil;
        } else if ((v = checkMaxInt(contextvmax)) != null) {
            v = randInt(contextrandom, (RubyIntegervtrue);
        } else if (!(v = TypeConverter.checkFloatType(context.runtimevmax)).isNil()) {
            double max = floatValue(v);
            if (max > 0.0) {
                v = context.runtime.newFloat(max * random.genrandReal());
            } else {
                v = context.nil;
            }
        } else if ((range = rangeValues(contextvmax)) != null) {
            if ((v = checkMaxInt(contextrange.range)) != null) {
                if (v instanceof RubyFixnum) {
                    long max = ((RubyFixnumv).getLongValue();
                    if (range.excl) {
                        max -= 1;
                    }
                    if (max >= 0) {
                        v = randLimitedFixnum(contextrandommax);
                    } else {
                        v = context.nil;
                    }
                } else if (v instanceof RubyBignum) {
                    BigInteger big = ((RubyBignumv).getBigIntegerValue();
                    if (!big.equals(.) && (big.signum() > 0)) {
                        if (range.excl) {
                            big = big.subtract(.);
                        }
                        v = randLimitedBignum(contextrandom, RubyBignum.newBignum(
                                context.runtimebig));
                    } else {
                        v = context.nil;
                    }
                } else {
                    v = context.nil;
                }
            } else if (!(v = TypeConverter.checkFloatType(context.runtimerange.range)).isNil()) {
                int scale = 1;
                double max = ((RubyFloatv).getDoubleValue();
                double mid = 0.5;
                double r = 0.0;
                if (Double.isInfinite(max)) {
                    double min = floatValue(range.begin) / 2.0;
                    max = floatValue(range.end) / 2.0;
                    scale = 2;
                    mid = max + min;
                    max -= min;
                } else {
                    floatValue(v);
                }
                v = context.nil;
                if (max > 0.0) {
                    if (range.excl) {
                        r = random.genrandReal();
                    } else {
                        r = random.genrandReal2();
                    }
                    if (scale > 1) {
                        return context.runtime.newFloat(+(+(+(r - 0.5) * max) * scale) + mid);
                    }
                    v = context.runtime.newFloat(r * max);
                } else if (max == 0.0 && !range.excl) {
                    v = context.runtime.newFloat(0.0);
                }
            }
        } else {
            v = context.nil;
            RubyNumeric.num2long(vmax); // need check here to raise TypeError
        }
        if (v.isNil()) {
            throw context.runtime.newArgumentError("invalid argument - " + vmax.toString());
        }
        if (range == null) {
            return v;
        }
        if ((range.begin instanceof RubyFixnum) && (v instanceof RubyFixnum)) {
            long x = ((RubyFixnumrange.begin).getLongValue() + ((RubyFixnumv).getLongValue();
            return context.runtime.newFixnum(x);
        }
        if (v instanceof RubyBignum) {
            return ((RubyBignumv).op_plus(contextrange.begin);
        } else if (v instanceof RubyFloat) {
            IRubyObject f = TypeConverter.checkFloatType(context.runtimerange.begin);
            if (!f.isNil()) {
                return ((RubyFloatv).op_plus(contextf);
            }
        }
        return RuntimeHelpers.invoke(contextrange.begin"+"v);
    }
    // c: float_value
    private static double floatValue(IRubyObject v) {
        double x;
        if (v instanceof RubyFloat) {
            x = ((RubyFloatv).getDoubleValue();
        } else if (v instanceof RubyNumeric) {
            x = ((RubyNumericv).convertToFloat().getDoubleValue();
        } else {
            throw v.getRuntime().newTypeError(vv.getRuntime().getFloat());
        }
        if (Double.isInfinite(x) || Double.isNaN(x)) {
            throw v.getRuntime().newErrnoEDOMError("Numerical argument out of domain");
        }
        return x;
    }
    private static IRubyObject checkMaxInt(ThreadContext contextIRubyObject vmax) {
        if (!(vmax instanceof RubyFloat)) {
            IRubyObject v = TypeConverter.checkIntegerType(context.runtimevmax"to_int");
            if (!v.isNil()) {
                return v;
            }
        }
        return null;
    }
    static class RangeLike {
        public IRubyObject begin = null;
        public IRubyObject end = null;
        boolean excl = false;
        public IRubyObject range = null;
    }
    private static RangeLike rangeValues(ThreadContext contextIRubyObject range) {
        RangeLike like = new RangeLike();
        if (range instanceof RubyRange) {
            RubyRange vrange = (RubyRangerange;
            like.begin = vrange.first();
            like.end = vrange.last();
            like.excl = vrange.exclude_end_p().isTrue();
        } else {
            if (!range.respondsTo("begin") || !range.respondsTo("end")
                    || !range.respondsTo("exclude_end?")) {
                return null;
            }
            like.begin = RuntimeHelpers.invoke(contextrange"begin");
            like.end = RuntimeHelpers.invoke(contextrange"end");
            like.excl = RuntimeHelpers.invoke(contextrange"exlucde_end?").isTrue();
        }
        like.range = RuntimeHelpers.invoke(contextlike.end"-"like.begin);
        return like;
    }
    @JRubyMethod(meta = true, compat = )
    public static IRubyObject srand(ThreadContext contextIRubyObject recv) {
        return srandCommon(contextrecv);
    }
    @JRubyMethod(meta = true, compat = )
    public static IRubyObject srand(ThreadContext contextIRubyObject recvIRubyObject seed) {
        return srandCommon(contextrecvseed);
    }
    // c: rb_f_srand
    public static IRubyObject srandCommon(ThreadContext contextIRubyObject recv) {
        return srandCommon(contextrecvrandomSeed(context.runtime));
    }
    // c: rb_f_srand
    public static IRubyObject srandCommon(ThreadContext contextIRubyObject recv,
            IRubyObject newSeed) {
        RandomType defaultRand = getDefaultRand(context);
        IRubyObject previousSeed = defaultRand.getSeed();
        defaultRand = new RandomType(newSeed);
        context.runtime.setDefaultRand(defaultRand);
        if (context.runtime.is1_9()) {
            ((RubyRandom) (context.runtime.getRandomClass())
                    .getConstant("DEFAULT")).setRandomType(defaultRand);
        }
        return previousSeed;
    }
    // c: random_equal
    @Override
    @JRubyMethod(name = "==", required = 1, compat = )
    public IRubyObject op_equal_19(ThreadContext contextIRubyObject obj) {
        if (!getType().equals(obj.getType())) {
            return context.runtime.getFalse();
        }
        return context.runtime.newBoolean(.equals(((RubyRandomobj).));
    }
    // c: random_state
    @JRubyMethod(name = "state", visibility = , compat = )
    public IRubyObject stateObj(ThreadContext context) {
        return .getState();
    }
    // c: random_left
    @JRubyMethod(name = "left", visibility = , compat = )
    public IRubyObject leftObj(ThreadContext context) {
        return RubyNumeric.int2fix(context.runtime.getLeft());
    }
    // c: random_s_state
    @JRubyMethod(name = "state", meta = true, visibility = , compat = )
    public static IRubyObject state(ThreadContext contextIRubyObject recv) {
        return getDefaultRand(context).getState();
    }
    // c: random_s_left
    @JRubyMethod(name = "left", meta = true, visibility = , compat = )
    public static IRubyObject left(ThreadContext contextIRubyObject recv) {
        return RubyNumeric.int2fix(context.runtimegetDefaultRand(context).getLeft());
    }
    // c: random_dump
    @JRubyMethod(name = "marshal_dump", compat = )
    public IRubyObject marshal_dump(ThreadContext context) {
        RubyBignum state = .getState();
        RubyInteger left = (RubyInteger) RubyNumeric.int2fix(context.runtime.getLeft());
        RubyArray dump = context.runtime.newArray(stateleft.getSeed());
        if (hasVariables()) {
            dump.syncVariables(this);
        }
        return dump;
    }
    // c: marshal_load
    @JRubyMethod(compat = )
    public IRubyObject marshal_load(ThreadContext contextIRubyObject arg) {
        RubyArray load = arg.convertToArray();
        if (load.size() != 3) {
            throw context.runtime.newArgumentError("wrong dump data");
        }
        if (!(load.eltInternal(0) instanceof RubyBignum)) {
            throw context.runtime.newTypeError(load.eltInternal(0), context.runtime.getBignum());
        }
        RubyBignum state = (RubyBignumload.eltInternal(0);
        int left = RubyNumeric.num2int(load.eltInternal(1));
        IRubyObject seed = load.eltInternal(2);
         = new RandomType(seedstateleft);
        if (load.hasVariables()) {
            syncVariables((IRubyObjectload);
        }
        return this;
    }
    // c: rb_random_bytes
    @JRubyMethod(name = "bytes", compat = )
    public IRubyObject bytes(ThreadContext contextIRubyObject arg) {
        int n = RubyNumeric.num2int(arg);
        byte[] bytes = new byte[n];
        int idx = 0;
        for (; n >= 4; n -= 4) {
            int r = .genrandInt32();
            for (int i = 0; i < 4; ++i) {
                bytes[idx++] = (byte) (r & 0xff);
                r >>>= 8;
            }
        }
        if (n > 0) {
            int r = .genrandInt32();
            for (int i = 0; i < n; ++i) {
                bytes[idx++] = (byte) (r & 0xff);
                r >>>= 8;
            }
        }
        return context.runtime.newString(new ByteList(bytes));
    }
    
    // c: rb_random_real
    public static double randomReal(ThreadContext contextIRubyObject obj) {
        RandomType random = null;
        if (obj.equals(context.runtime.getRandomClass())) {
            random = getDefaultRand(context);
        }
        if (obj instanceof RubyRandom) {
            random = ((RubyRandomobj).;
        }
        if (random != null) {
            return random.genrandReal();
        }
        double d = RubyNumeric.num2dbl(RuntimeHelpers.invoke(contextobj"rand"));
        if (d < 0.0 || d >= 1.0) {
            throw context.runtime.newRangeError("random number too big: " + d);
        }
        return d;
    }
    
    @JRubyMethod(name = "new_seed", meta = true, compat = )
    public static IRubyObject newSeed(ThreadContext contextIRubyObject recv) {
        return randomSeed(context.runtime);
    }
    private void setRandomType(RandomType random) {
        this. = random;
    }