View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.rng.core.source32;
19  
20  import org.apache.commons.rng.core.util.NumberFactory;
21  import org.apache.commons.rng.core.BaseProvider;
22  
23  /**
24   * Base class for all implementations that provide an {@code int}-based
25   * source randomness.
26   */
27  public abstract class IntProvider
28      extends BaseProvider
29      implements RandomIntSource {
30  
31      /** Empty boolean source. This is the location of the sign-bit after 31 right shifts on
32       * the boolean source. */
33      private static final int EMPTY_BOOL_SOURCE = 1;
34  
35      /**
36       * Provides a bit source for booleans.
37       *
38       * <p>A cached value from a call to {@link #next()}.
39       *
40       * <p>Only stores 31-bits when full as 1 bit has already been consumed.
41       * The sign bit is a flag that shifts down so the source eventually equals 1
42       * when all bits are consumed and will trigger a refill.
43       */
44      private int booleanSource = EMPTY_BOOL_SOURCE;
45  
46      /**
47       * Creates a new instance.
48       */
49      public IntProvider() {
50          super();
51      }
52  
53      /**
54       * Creates a new instance copying the state from the source.
55       *
56       * <p>This provides base functionality to allow a generator to create a copy, for example
57       * for use in the {@link org.apache.commons.rng.JumpableUniformRandomProvider
58       * JumpableUniformRandomProvider} interface.
59       *
60       * @param source Source to copy.
61       * @since 1.3
62       */
63      protected IntProvider(IntProvider source) {
64          booleanSource = source.booleanSource;
65      }
66  
67      /**
68       * Reset the cached state used in the default implementation of {@link #nextBoolean()}.
69       *
70       * <p>This should be used when the state is no longer valid, for example after a jump
71       * performed for the {@link org.apache.commons.rng.JumpableUniformRandomProvider
72       * JumpableUniformRandomProvider} interface.</p>
73       *
74       * @since 1.3
75       */
76      protected void resetCachedState() {
77          booleanSource = EMPTY_BOOL_SOURCE;
78      }
79  
80      /** {@inheritDoc} */
81      @Override
82      protected byte[] getStateInternal() {
83          return composeStateInternal(NumberFactory.makeByteArray(booleanSource),
84                                      super.getStateInternal());
85      }
86  
87      /** {@inheritDoc} */
88      @Override
89      protected void setStateInternal(byte[] s) {
90          final byte[][] c = splitStateInternal(s, Integer.BYTES);
91          booleanSource = NumberFactory.makeInt(c[0]);
92          super.setStateInternal(c[1]);
93      }
94  
95      /** {@inheritDoc} */
96      @Override
97      public int nextInt() {
98          return next();
99      }
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 }