001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.rng.core.source32;
019
020import org.apache.commons.rng.core.util.NumberFactory;
021import org.apache.commons.rng.core.BaseProvider;
022
023/**
024 * Base class for all implementations that provide an {@code int}-based
025 * source randomness.
026 */
027public abstract class IntProvider
028    extends BaseProvider
029    implements RandomIntSource {
030
031    /** {@inheritDoc} */
032    @Override
033    public int nextInt() {
034        return next();
035    }
036
037    /** {@inheritDoc} */
038    @Override
039    public boolean nextBoolean() {
040        return NumberFactory.makeBoolean(nextInt());
041    }
042
043    /** {@inheritDoc} */
044    @Override
045    public double nextDouble() {
046        return NumberFactory.makeDouble(nextInt(), nextInt());
047    }
048
049    /** {@inheritDoc} */
050    @Override
051    public float nextFloat() {
052        return NumberFactory.makeFloat(nextInt());
053    }
054
055    /** {@inheritDoc} */
056    @Override
057    public long nextLong() {
058        return NumberFactory.makeLong(nextInt(), nextInt());
059    }
060
061    /** {@inheritDoc} */
062    @Override
063    public void nextBytes(byte[] bytes) {
064        nextBytesFill(this, bytes, 0, bytes.length);
065    }
066
067    /** {@inheritDoc} */
068    @Override
069    public void nextBytes(byte[] bytes,
070                          int start,
071                          int len) {
072        checkIndex(0, bytes.length - 1, start);
073        checkIndex(0, bytes.length - start, len);
074
075        nextBytesFill(this, bytes, start, len);
076    }
077
078    /**
079     * Generates random bytes and places them into a user-supplied array.
080     *
081     * <p>
082     * The array is filled with bytes extracted from random {@code int} values.
083     * This implies that the number of random bytes generated may be larger than
084     * the length of the byte array.
085     * </p>
086     *
087     * @param source Source of randomness.
088     * @param bytes Array in which to put the generated bytes. Cannot be null.
089     * @param start Index at which to start inserting the generated bytes.
090     * @param len Number of bytes to insert.
091     */
092    static void nextBytesFill(RandomIntSource source,
093                              byte[] bytes,
094                              int start,
095                              int len) {
096        int index = start; // Index of first insertion.
097
098        // Index of first insertion plus multiple of 4 part of length
099        // (i.e. length with 2 least significant bits unset).
100        final int indexLoopLimit = index + (len & 0x7ffffffc);
101
102        // Start filling in the byte array, 4 bytes at a time.
103        while (index < indexLoopLimit) {
104            final int random = source.next();
105            bytes[index++] = (byte) random;
106            bytes[index++] = (byte) (random >>> 8);
107            bytes[index++] = (byte) (random >>> 16);
108            bytes[index++] = (byte) (random >>> 24);
109        }
110
111        final int indexLimit = start + len; // Index of last insertion + 1.
112
113        // Fill in the remaining bytes.
114        if (index < indexLimit) {
115            int random = source.next();
116            while (true) {
117                bytes[index++] = (byte) random;
118                if (index < indexLimit) {
119                    random >>>= 8;
120                } else {
121                    break;
122                }
123            }
124        }
125    }
126}