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    /**
032     * Provides a bit source for booleans.
033     *
034     * <p>A cached value from a call to {@link #nextInt()}.
035     */
036    private int booleanSource; // Initialised as 0
037
038    /**
039     * The bit mask of the boolean source to obtain the boolean bit.
040     *
041     * <p>The bit mask contains a single bit set. This begins at the least
042     * significant bit and is gradually shifted upwards until overflow to zero.
043     *
044     * <p>When zero a new boolean source should be created and the mask set to the
045     * least significant bit (i.e. 1).
046     */
047    private int booleanBitMask; // Initialised as 0
048
049    /**
050     * Creates a new instance.
051     */
052    public IntProvider() {
053        super();
054    }
055
056    /**
057     * Creates a new instance copying the state from the source.
058     *
059     * <p>This provides base functionality to allow a generator to create a copy, for example
060     * for use in the {@link org.apache.commons.rng.JumpableUniformRandomProvider
061     * JumpableUniformRandomProvider} interface.
062     *
063     * @param source Source to copy.
064     * @since 1.3
065     */
066    protected IntProvider(IntProvider source) {
067        booleanSource = source.booleanSource;
068        booleanBitMask = source.booleanBitMask;
069    }
070
071    /**
072     * Reset the cached state used in the default implementation of {@link #nextBoolean()}.
073     *
074     * <p>This should be used when the state is no longer valid, for example after a jump
075     * performed for the {@link org.apache.commons.rng.JumpableUniformRandomProvider
076     * JumpableUniformRandomProvider} interface.</p>
077     *
078     * @since 1.3
079     */
080    protected void resetCachedState() {
081        booleanSource = 0;
082        booleanBitMask = 0;
083    }
084
085    /** {@inheritDoc} */
086    @Override
087    protected byte[] getStateInternal() {
088        final int[] state = {booleanSource,
089                             booleanBitMask};
090        return composeStateInternal(NumberFactory.makeByteArray(state),
091                                    super.getStateInternal());
092    }
093
094    /** {@inheritDoc} */
095    @Override
096    protected void setStateInternal(byte[] s) {
097        final byte[][] c = splitStateInternal(s, 8);
098        final int[] state = NumberFactory.makeIntArray(c[0]);
099        booleanSource  = state[0];
100        booleanBitMask = state[1];
101        super.setStateInternal(c[1]);
102    }
103
104    /** {@inheritDoc} */
105    @Override
106    public int nextInt() {
107        return next();
108    }
109
110    /** {@inheritDoc} */
111    @Override
112    public boolean nextBoolean() {
113        // Shift up. This will eventually overflow and become zero.
114        booleanBitMask <<= 1;
115        // The mask will either contain a single bit or none.
116        if (booleanBitMask == 0) {
117            // Set the least significant bit
118            booleanBitMask = 1;
119            // Get the next value
120            booleanSource = nextInt();
121        }
122        // Return if the bit is set
123        return (booleanSource & booleanBitMask) != 0;
124    }
125
126    /** {@inheritDoc} */
127    @Override
128    public double nextDouble() {
129        return NumberFactory.makeDouble(nextInt(), nextInt());
130    }
131
132    /** {@inheritDoc} */
133    @Override
134    public float nextFloat() {
135        return NumberFactory.makeFloat(nextInt());
136    }
137
138    /** {@inheritDoc} */
139    @Override
140    public long nextLong() {
141        return NumberFactory.makeLong(nextInt(), nextInt());
142    }
143
144    /** {@inheritDoc} */
145    @Override
146    public void nextBytes(byte[] bytes) {
147        nextBytesFill(this, bytes, 0, bytes.length);
148    }
149
150    /** {@inheritDoc} */
151    @Override
152    public void nextBytes(byte[] bytes,
153                          int start,
154                          int len) {
155        checkIndex(0, bytes.length - 1, start);
156        checkIndex(0, bytes.length - start, len);
157
158        nextBytesFill(this, bytes, start, len);
159    }
160
161    /**
162     * Generates random bytes and places them into a user-supplied array.
163     *
164     * <p>
165     * The array is filled with bytes extracted from random {@code int} values.
166     * This implies that the number of random bytes generated may be larger than
167     * the length of the byte array.
168     * </p>
169     *
170     * @param source Source of randomness.
171     * @param bytes Array in which to put the generated bytes. Cannot be null.
172     * @param start Index at which to start inserting the generated bytes.
173     * @param len Number of bytes to insert.
174     */
175    static void nextBytesFill(RandomIntSource source,
176                              byte[] bytes,
177                              int start,
178                              int len) {
179        int index = start; // Index of first insertion.
180
181        // Index of first insertion plus multiple of 4 part of length
182        // (i.e. length with 2 least significant bits unset).
183        final int indexLoopLimit = index + (len & 0x7ffffffc);
184
185        // Start filling in the byte array, 4 bytes at a time.
186        while (index < indexLoopLimit) {
187            final int random = source.next();
188            bytes[index++] = (byte) random;
189            bytes[index++] = (byte) (random >>> 8);
190            bytes[index++] = (byte) (random >>> 16);
191            bytes[index++] = (byte) (random >>> 24);
192        }
193
194        final int indexLimit = start + len; // Index of last insertion + 1.
195
196        // Fill in the remaining bytes.
197        if (index < indexLimit) {
198            int random = source.next();
199            while (true) {
200                bytes[index++] = (byte) random;
201                if (index < indexLimit) {
202                    random >>>= 8;
203                } else {
204                    break;
205                }
206            }
207        }
208    }
209}