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    /** Empty boolean source. This is the location of the sign-bit after 31 right shifts on
032     * the boolean source. */
033    private static final int EMPTY_BOOL_SOURCE = 1;
034
035    /**
036     * Provides a bit source for booleans.
037     *
038     * <p>A cached value from a call to {@link #next()}.
039     *
040     * <p>Only stores 31-bits when full as 1 bit has already been consumed.
041     * The sign bit is a flag that shifts down so the source eventually equals 1
042     * when all bits are consumed and will trigger a refill.
043     */
044    private int booleanSource = EMPTY_BOOL_SOURCE;
045
046    /**
047     * Creates a new instance.
048     */
049    public IntProvider() {
050        super();
051    }
052
053    /**
054     * Creates a new instance copying the state from the source.
055     *
056     * <p>This provides base functionality to allow a generator to create a copy, for example
057     * for use in the {@link org.apache.commons.rng.JumpableUniformRandomProvider
058     * JumpableUniformRandomProvider} interface.
059     *
060     * @param source Source to copy.
061     * @since 1.3
062     */
063    protected IntProvider(IntProvider source) {
064        booleanSource = source.booleanSource;
065    }
066
067    /**
068     * Reset the cached state used in the default implementation of {@link #nextBoolean()}.
069     *
070     * <p>This should be used when the state is no longer valid, for example after a jump
071     * performed for the {@link org.apache.commons.rng.JumpableUniformRandomProvider
072     * JumpableUniformRandomProvider} interface.</p>
073     *
074     * @since 1.3
075     */
076    protected void resetCachedState() {
077        booleanSource = EMPTY_BOOL_SOURCE;
078    }
079
080    /** {@inheritDoc} */
081    @Override
082    protected byte[] getStateInternal() {
083        return composeStateInternal(NumberFactory.makeByteArray(booleanSource),
084                                    super.getStateInternal());
085    }
086
087    /** {@inheritDoc} */
088    @Override
089    protected void setStateInternal(byte[] s) {
090        final byte[][] c = splitStateInternal(s, Integer.BYTES);
091        booleanSource = NumberFactory.makeInt(c[0]);
092        super.setStateInternal(c[1]);
093    }
094
095    /** {@inheritDoc} */
096    @Override
097    public int nextInt() {
098        return next();
099    }
100
101    /** {@inheritDoc} */
102    @Override
103    public boolean nextBoolean() {
104        int bits = booleanSource;
105        if (bits == 1) {
106            // Refill
107            bits = next();
108            // Store a refill flag in the sign bit and the unused 31 bits, return lowest bit
109            booleanSource = Integer.MIN_VALUE | (bits >>> 1);
110            return (bits & 0x1) == 1;
111        }
112        // Shift down eventually triggering refill, return current lowest bit
113        booleanSource = bits >>> 1;
114        return (bits & 0x1) == 1;
115    }
116
117    /** {@inheritDoc} */
118    @Override
119    public double nextDouble() {
120        return NumberFactory.makeDouble(next(), next());
121    }
122
123    /** {@inheritDoc} */
124    @Override
125    public long nextLong() {
126        return NumberFactory.makeLong(next(), next());
127    }
128
129    /** {@inheritDoc} */
130    @Override
131    public void nextBytes(byte[] bytes) {
132        nextBytesFill(this, bytes, 0, bytes.length);
133    }
134
135    /** {@inheritDoc} */
136    @Override
137    public void nextBytes(byte[] bytes,
138                          int start,
139                          int len) {
140        checkFromIndexSize(start, len, bytes.length);
141        nextBytesFill(this, bytes, start, len);
142    }
143
144    /**
145     * Generates random bytes and places them into a user-supplied array.
146     *
147     * <p>
148     * The array is filled with bytes extracted from random {@code int} values.
149     * This implies that the number of random bytes generated may be larger than
150     * the length of the byte array.
151     * </p>
152     *
153     * @param source Source of randomness.
154     * @param bytes Array in which to put the generated bytes. Cannot be null.
155     * @param start Index at which to start inserting the generated bytes.
156     * @param len Number of bytes to insert.
157     */
158    static void nextBytesFill(RandomIntSource source,
159                              byte[] bytes,
160                              int start,
161                              int len) {
162        int index = start; // Index of first insertion.
163
164        // Index of first insertion plus multiple of 4 part of length
165        // (i.e. length with 2 least significant bits unset).
166        final int indexLoopLimit = index + (len & 0x7ffffffc);
167
168        // Start filling in the byte array, 4 bytes at a time.
169        while (index < indexLoopLimit) {
170            final int random = source.next();
171            bytes[index++] = (byte) random;
172            bytes[index++] = (byte) (random >>> 8);
173            bytes[index++] = (byte) (random >>> 16);
174            bytes[index++] = (byte) (random >>> 24);
175        }
176
177        final int indexLimit = start + len; // Index of last insertion + 1.
178
179        // Fill in the remaining bytes.
180        if (index < indexLimit) {
181            int random = source.next();
182            while (true) {
183                bytes[index++] = (byte) random;
184                if (index < indexLimit) {
185                    random >>>= 8;
186                } else {
187                    break;
188                }
189            }
190        }
191    }
192
193    /**
194     * Checks if the sub-range from fromIndex (inclusive) to fromIndex + size (exclusive) is
195     * within the bounds of range from 0 (inclusive) to length (exclusive).
196     *
197     * <p>This function provides the functionality of
198     * {@code java.utils.Objects.checkFromIndexSize} introduced in JDK 9. The
199     * <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Objects.html#checkFromIndexSize(int,int,int)">Objects</a>
200     * javadoc has been reproduced for reference.
201     *
202     * <p>The sub-range is defined to be out of bounds if any of the following inequalities
203     * is true:
204     * <ul>
205     * <li>{@code fromIndex < 0}
206     * <li>{@code size < 0}
207     * <li>{@code fromIndex + size > length}, taking into account integer overflow
208     * <li>{@code length < 0}, which is implied from the former inequalities
209     * </ul>
210     *
211     * @param fromIndex the lower-bound (inclusive) of the sub-interval
212     * @param size the size of the sub-range
213     * @param length the upper-bound (exclusive) of the range
214     * @return the fromIndex
215     * @throws IndexOutOfBoundsException if the sub-range is out of bounds
216     */
217    private static int checkFromIndexSize(int fromIndex, int size, int length) {
218        // check for any negatives,
219        // or overflow safe length check given the values are all positive
220        // remaining = length - fromIndex
221        if ((fromIndex | size | length) < 0 || size > length - fromIndex) {
222            throw new IndexOutOfBoundsException(
223                // Note: %<d is 'relative indexing' to re-use the last argument
224                String.format("Range [%d, %<d + %d) out of bounds for length %d",
225                    fromIndex, size, length));
226        }
227        return fromIndex;
228    }
229}