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 }