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.source64;
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 a {@code long}-based
025 * source randomness.
026 */
027public abstract class LongProvider
028    extends BaseProvider
029    implements RandomLongSource {
030
031    /**
032     * Provides a bit source for booleans.
033     *
034     * <p>A cached value from a call to {@link #nextLong()}.
035     */
036    private long 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 long booleanBitMask; // Initialised as 0
048
049    /**
050     * Provides a source for ints.
051     *
052     * <p>A cached value from a call to {@link #nextLong()}.
053     */
054    private long intSource;
055
056    /** Flag to indicate an int source has been cached. */
057    private boolean cachedIntSource; // Initialised as false
058
059    /**
060     * Creates a new instance.
061     */
062    public LongProvider() {
063        super();
064    }
065
066    /**
067     * Creates a new instance copying the state from the source.
068     *
069     * <p>This provides base functionality to allow a generator to create a copy, for example
070     * for use in the {@link org.apache.commons.rng.JumpableUniformRandomProvider
071     * JumpableUniformRandomProvider} interface.
072     *
073     * @param source Source to copy.
074     * @since 1.3
075     */
076    protected LongProvider(LongProvider source) {
077        booleanSource = source.booleanSource;
078        booleanBitMask = source.booleanBitMask;
079        intSource = source.intSource;
080        cachedIntSource = source.cachedIntSource;
081    }
082
083    /**
084     * Reset the cached state used in the default implementation of {@link #nextBoolean()}
085     * and {@link #nextInt()}.
086     *
087     * <p>This should be used when the state is no longer valid, for example after a jump
088     * performed for the {@link org.apache.commons.rng.JumpableUniformRandomProvider
089     * JumpableUniformRandomProvider} interface.</p>
090     *
091     * @since 1.3
092     */
093    protected void resetCachedState() {
094        booleanSource = 0L;
095        booleanBitMask = 0L;
096        intSource = 0L;
097        cachedIntSource = false;
098    }
099
100    /** {@inheritDoc} */
101    @Override
102    protected byte[] getStateInternal() {
103        // Pack the boolean inefficiently as a long
104        final long[] state = {booleanSource,
105                              booleanBitMask,
106                              intSource,
107                              cachedIntSource ? 1 : 0 };
108        return composeStateInternal(NumberFactory.makeByteArray(state),
109                                    super.getStateInternal());
110    }
111
112    /** {@inheritDoc} */
113    @Override
114    protected void setStateInternal(byte[] s) {
115        final byte[][] c = splitStateInternal(s, 32);
116        final long[] state = NumberFactory.makeLongArray(c[0]);
117        booleanSource   = state[0];
118        booleanBitMask  = state[1];
119        intSource       = state[2];
120        // Non-zero is true
121        cachedIntSource = state[3] != 0;
122        super.setStateInternal(c[1]);
123    }
124
125    /** {@inheritDoc} */
126    @Override
127    public long nextLong() {
128        return next();
129    }
130
131    /** {@inheritDoc} */
132    @Override
133    public int nextInt() {
134        // Directly store and use the long value as a source for ints
135        if (cachedIntSource) {
136            // Consume the cache value
137            cachedIntSource = false;
138            // Return the lower 32 bits
139            return NumberFactory.extractLo(intSource);
140        }
141        // Fill the cache
142        cachedIntSource = true;
143        intSource = nextLong();
144        // Return the upper 32 bits
145        return NumberFactory.extractHi(intSource);
146    }
147
148    /** {@inheritDoc} */
149    @Override
150    public double nextDouble() {
151        return NumberFactory.makeDouble(nextLong());
152    }
153
154    /** {@inheritDoc} */
155    @Override
156    public boolean nextBoolean() {
157        // Shift up. This will eventually overflow and become zero.
158        booleanBitMask <<= 1;
159        // The mask will either contain a single bit or none.
160        if (booleanBitMask == 0) {
161            // Set the least significant bit
162            booleanBitMask = 1;
163            // Get the next value
164            booleanSource = nextLong();
165        }
166        // Return if the bit is set
167        return (booleanSource & booleanBitMask) != 0;
168    }
169
170    /** {@inheritDoc} */
171    @Override
172    public float nextFloat() {
173        return NumberFactory.makeFloat(nextInt());
174    }
175
176    /** {@inheritDoc} */
177    @Override
178    public void nextBytes(byte[] bytes) {
179        nextBytesFill(this, bytes, 0, bytes.length);
180    }
181
182    /** {@inheritDoc} */
183    @Override
184    public void nextBytes(byte[] bytes,
185                          int start,
186                          int len) {
187        checkIndex(0, bytes.length - 1, start);
188        checkIndex(0, bytes.length - start, len);
189
190        nextBytesFill(this, bytes, start, len);
191    }
192
193    /**
194     * Generates random bytes and places them into a user-supplied array.
195     *
196     * <p>
197     * The array is filled with bytes extracted from random {@code long} values.
198     * This implies that the number of random bytes generated may be larger than
199     * the length of the byte array.
200     * </p>
201     *
202     * @param source Source of randomness.
203     * @param bytes Array in which to put the generated bytes. Cannot be null.
204     * @param start Index at which to start inserting the generated bytes.
205     * @param len Number of bytes to insert.
206     */
207    static void nextBytesFill(RandomLongSource source,
208                              byte[] bytes,
209                              int start,
210                              int len) {
211        int index = start; // Index of first insertion.
212
213        // Index of first insertion plus multiple of 8 part of length
214        // (i.e. length with 3 least significant bits unset).
215        final int indexLoopLimit = index + (len & 0x7ffffff8);
216
217        // Start filling in the byte array, 8 bytes at a time.
218        while (index < indexLoopLimit) {
219            final long random = source.next();
220            bytes[index++] = (byte) random;
221            bytes[index++] = (byte) (random >>> 8);
222            bytes[index++] = (byte) (random >>> 16);
223            bytes[index++] = (byte) (random >>> 24);
224            bytes[index++] = (byte) (random >>> 32);
225            bytes[index++] = (byte) (random >>> 40);
226            bytes[index++] = (byte) (random >>> 48);
227            bytes[index++] = (byte) (random >>> 56);
228        }
229
230        final int indexLimit = start + len; // Index of last insertion + 1.
231
232        // Fill in the remaining bytes.
233        if (index < indexLimit) {
234            long random = source.next();
235            while (true) {
236                bytes[index++] = (byte) random;
237                if (index < indexLimit) {
238                    random >>>= 8;
239                } else {
240                    break;
241                }
242            }
243        }
244    }
245}