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.source64;
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 a {@code long}-based
25   * source randomness.
26   */
27  public abstract class LongProvider
28      extends BaseProvider
29      implements RandomLongSource {
30  
31      /**
32       * Provides a bit source for booleans.
33       *
34       * <p>A cached value from a call to {@link #nextLong()}.
35       */
36      private long booleanSource; // Initialised as 0
37  
38      /**
39       * The bit mask of the boolean source to obtain the boolean bit.
40       *
41       * <p>The bit mask contains a single bit set. This begins at the least
42       * significant bit and is gradually shifted upwards until overflow to zero.
43       *
44       * <p>When zero a new boolean source should be created and the mask set to the
45       * least significant bit (i.e. 1).
46       */
47      private long booleanBitMask; // Initialised as 0
48  
49      /**
50       * Provides a source for ints.
51       *
52       * <p>A cached value from a call to {@link #nextLong()}.
53       */
54      private long intSource;
55  
56      /** Flag to indicate an int source has been cached. */
57      private boolean cachedIntSource; // Initialised as false
58  
59      /** {@inheritDoc} */
60      @Override
61      protected byte[] getStateInternal() {
62          // Pack the boolean inefficiently as a long
63          final long[] state = new long[] { booleanSource,
64                                            booleanBitMask,
65                                            intSource,
66                                            cachedIntSource ? 1 : 0 };
67          return composeStateInternal(super.getStateInternal(),
68                                      NumberFactory.makeByteArray(state));
69      }
70  
71      /** {@inheritDoc} */
72      @Override
73      protected void setStateInternal(byte[] s) {
74          final byte[][] c = splitStateInternal(s, 32);
75          final long[] state = NumberFactory.makeLongArray(c[0]);
76          booleanSource   = state[0];
77          booleanBitMask  = state[1];
78          intSource       = state[2];
79          // Non-zero is true
80          cachedIntSource = state[3] != 0;
81          super.setStateInternal(c[1]);
82      }
83  
84      /** {@inheritDoc} */
85      @Override
86      public long nextLong() {
87          return next();
88      }
89  
90      /** {@inheritDoc} */
91      @Override
92      public int nextInt() {
93          // Directly store and use the long value as a source for ints
94          if (cachedIntSource) {
95              // Consume the cache value
96              cachedIntSource = false;
97              // Return the lower 32 bits
98              return NumberFactory.extractLo(intSource);
99          }
100         // Fill the cache
101         cachedIntSource = true;
102         intSource = nextLong();
103         // Return the upper 32 bits
104         return NumberFactory.extractHi(intSource);
105     }
106 
107     /** {@inheritDoc} */
108     @Override
109     public double nextDouble() {
110         return NumberFactory.makeDouble(nextLong());
111     }
112 
113     /** {@inheritDoc} */
114     @Override
115     public boolean nextBoolean() {
116         // Shift up. This will eventually overflow and become zero.
117         booleanBitMask <<= 1;
118         // The mask will either contain a single bit or none.
119         if (booleanBitMask == 0) {
120             // Set the least significant bit
121             booleanBitMask = 1;
122             // Get the next value
123             booleanSource = nextLong();
124         }
125         // Return if the bit is set
126         return (booleanSource & booleanBitMask) != 0;
127     }
128 
129     /** {@inheritDoc} */
130     @Override
131     public float nextFloat() {
132         return NumberFactory.makeFloat(nextInt());
133     }
134 
135     /** {@inheritDoc} */
136     @Override
137     public void nextBytes(byte[] bytes) {
138         nextBytesFill(this, bytes, 0, bytes.length);
139     }
140 
141     /** {@inheritDoc} */
142     @Override
143     public void nextBytes(byte[] bytes,
144                           int start,
145                           int len) {
146         checkIndex(0, bytes.length - 1, start);
147         checkIndex(0, bytes.length - start, len);
148 
149         nextBytesFill(this, bytes, start, len);
150     }
151 
152     /**
153      * Generates random bytes and places them into a user-supplied array.
154      *
155      * <p>
156      * The array is filled with bytes extracted from random {@code long} values.
157      * This implies that the number of random bytes generated may be larger than
158      * the length of the byte array.
159      * </p>
160      *
161      * @param source Source of randomness.
162      * @param bytes Array in which to put the generated bytes. Cannot be null.
163      * @param start Index at which to start inserting the generated bytes.
164      * @param len Number of bytes to insert.
165      */
166     static void nextBytesFill(RandomLongSource source,
167                               byte[] bytes,
168                               int start,
169                               int len) {
170         int index = start; // Index of first insertion.
171 
172         // Index of first insertion plus multiple of 8 part of length
173         // (i.e. length with 3 least significant bits unset).
174         final int indexLoopLimit = index + (len & 0x7ffffff8);
175 
176         // Start filling in the byte array, 8 bytes at a time.
177         while (index < indexLoopLimit) {
178             final long random = source.next();
179             bytes[index++] = (byte) random;
180             bytes[index++] = (byte) (random >>> 8);
181             bytes[index++] = (byte) (random >>> 16);
182             bytes[index++] = (byte) (random >>> 24);
183             bytes[index++] = (byte) (random >>> 32);
184             bytes[index++] = (byte) (random >>> 40);
185             bytes[index++] = (byte) (random >>> 48);
186             bytes[index++] = (byte) (random >>> 56);
187         }
188 
189         final int indexLimit = start + len; // Index of last insertion + 1.
190 
191         // Fill in the remaining bytes.
192         if (index < indexLimit) {
193             long random = source.next();
194             while (true) {
195                 bytes[index++] = (byte) random;
196                 if (index < indexLimit) {
197                     random >>>= 8;
198                 } else {
199                     break;
200                 }
201             }
202         }
203     }
204 }