UniformRandomProviderSupport.java

  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. package org.apache.commons.rng;

  18. import java.util.Objects;
  19. import java.util.Spliterator;
  20. import java.util.function.Consumer;
  21. import java.util.function.DoubleConsumer;
  22. import java.util.function.IntConsumer;
  23. import java.util.function.LongConsumer;
  24. import java.util.function.ToDoubleFunction;
  25. import java.util.function.ToIntFunction;
  26. import java.util.function.ToLongFunction;

  27. /**
  28.  * Support for {@link UniformRandomProvider} default methods.
  29.  *
  30.  * @since 1.5
  31.  */
  32. final class UniformRandomProviderSupport {
  33.     /** Message for an invalid stream size. */
  34.     private static final String INVALID_STREAM_SIZE = "Invalid stream size: ";
  35.     /** Message for an invalid upper bound (must be positive, finite and above zero). */
  36.     private static final String INVALID_UPPER_BOUND = "Upper bound must be above zero: ";
  37.     /** Message format for an invalid range for lower inclusive and upper exclusive. */
  38.     private static final String INVALID_RANGE = "Invalid range: [%s, %s)";
  39.     /** 2^32. */
  40.     private static final long POW_32 = 1L << 32;
  41.     /** Message when the consumer action is null. */
  42.     private static final String NULL_ACTION = "action must not be null";

  43.     /** No instances. */
  44.     private UniformRandomProviderSupport() {}

  45.     /**
  46.      * Validate the stream size.
  47.      *
  48.      * @param size Stream size.
  49.      * @throws IllegalArgumentException if {@code size} is negative.
  50.      */
  51.     static void validateStreamSize(long size) {
  52.         if (size < 0) {
  53.             throw new IllegalArgumentException(INVALID_STREAM_SIZE + size);
  54.         }
  55.     }

  56.     /**
  57.      * Validate the upper bound.
  58.      *
  59.      * @param bound Upper bound (exclusive) on the random number to be returned.
  60.      * @throws IllegalArgumentException if {@code bound} is equal to or less than zero.
  61.      */
  62.     static void validateUpperBound(int bound) {
  63.         if (bound <= 0) {
  64.             throw new IllegalArgumentException(INVALID_UPPER_BOUND + bound);
  65.         }
  66.     }

  67.     /**
  68.      * Validate the upper bound.
  69.      *
  70.      * @param bound Upper bound (exclusive) on the random number to be returned.
  71.      * @throws IllegalArgumentException if {@code bound} is equal to or less than zero.
  72.      */
  73.     static void validateUpperBound(long bound) {
  74.         if (bound <= 0) {
  75.             throw new IllegalArgumentException(INVALID_UPPER_BOUND + bound);
  76.         }
  77.     }

  78.     /**
  79.      * Validate the upper bound.
  80.      *
  81.      * @param bound Upper bound (exclusive) on the random number to be returned.
  82.      * @throws IllegalArgumentException if {@code bound} is equal to or less than zero, or
  83.      * is not finite
  84.      */
  85.     static void validateUpperBound(float bound) {
  86.         // Negation of logic will detect NaN
  87.         if (!(bound > 0 && bound <= Float.MAX_VALUE)) {
  88.             throw new IllegalArgumentException(INVALID_UPPER_BOUND + bound);
  89.         }
  90.     }

  91.     /**
  92.      * Validate the upper bound.
  93.      *
  94.      * @param bound Upper bound (exclusive) on the random number to be returned.
  95.      * @throws IllegalArgumentException if {@code bound} is equal to or less than zero, or
  96.      * is not finite
  97.      */
  98.     static void validateUpperBound(double bound) {
  99.         // Negation of logic will detect NaN
  100.         if (!(bound > 0 && bound <= Double.MAX_VALUE)) {
  101.             throw new IllegalArgumentException(INVALID_UPPER_BOUND + bound);
  102.         }
  103.     }

  104.     /**
  105.      * Validate the range between the specified {@code origin} (inclusive) and the
  106.      * specified {@code bound} (exclusive).
  107.      *
  108.      * @param origin Lower bound on the random number to be returned.
  109.      * @param bound Upper bound (exclusive) on the random number to be returned.
  110.      * @throws IllegalArgumentException if {@code origin} is greater than or equal to
  111.      * {@code bound}.
  112.      */
  113.     static void validateRange(int origin, int bound) {
  114.         if (origin >= bound) {
  115.             throw new IllegalArgumentException(String.format(INVALID_RANGE, origin, bound));
  116.         }
  117.     }

  118.     /**
  119.      * Validate the range between the specified {@code origin} (inclusive) and the
  120.      * specified {@code bound} (exclusive).
  121.      *
  122.      * @param origin Lower bound on the random number to be returned.
  123.      * @param bound Upper bound (exclusive) on the random number to be returned.
  124.      * @throws IllegalArgumentException if {@code origin} is greater than or equal to
  125.      * {@code bound}.
  126.      */
  127.     static void validateRange(long origin, long bound) {
  128.         if (origin >= bound) {
  129.             throw new IllegalArgumentException(String.format(INVALID_RANGE, origin, bound));
  130.         }
  131.     }

  132.     /**
  133.      * Validate the range between the specified {@code origin} (inclusive) and the
  134.      * specified {@code bound} (exclusive).
  135.      *
  136.      * @param origin Lower bound on the random number to be returned.
  137.      * @param bound Upper bound (exclusive) on the random number to be returned.
  138.      * @throws IllegalArgumentException if {@code origin} is not finite, or {@code bound}
  139.      * is not finite, or {@code origin} is greater than or equal to {@code bound}.
  140.      */
  141.     static void validateRange(double origin, double bound) {
  142.         if (origin >= bound || !Double.isFinite(origin) || !Double.isFinite(bound)) {
  143.             throw new IllegalArgumentException(String.format(INVALID_RANGE, origin, bound));
  144.         }
  145.     }

  146.     /**
  147.      * Checks if the sub-range from fromIndex (inclusive) to fromIndex + size (exclusive) is
  148.      * within the bounds of range from 0 (inclusive) to length (exclusive).
  149.      *
  150.      * <p>This function provides the functionality of
  151.      * {@code java.utils.Objects.checkFromIndexSize} introduced in JDK 9. The
  152.      * <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Objects.html#checkFromIndexSize(int,int,int)">Objects</a>
  153.      * javadoc has been reproduced for reference.
  154.      *
  155.      * <p>The sub-range is defined to be out of bounds if any of the following inequalities
  156.      * is true:
  157.      * <ul>
  158.      * <li>{@code fromIndex < 0}
  159.      * <li>{@code size < 0}
  160.      * <li>{@code fromIndex + size > length}, taking into account integer overflow
  161.      * <li>{@code length < 0}, which is implied from the former inequalities
  162.      * </ul>
  163.      *
  164.      * <p>Note: This is not an exact implementation of the functionality of
  165.      * {@code Objects.checkFromIndexSize}. The following changes have been made:
  166.      * <ul>
  167.      * <li>The method signature has been changed to avoid the return of {@code fromIndex};
  168.      * this value is not used within this package.
  169.      * <li>No checks are made for {@code length < 0} as this is assumed to be derived from
  170.      * an array length.
  171.      * </ul>
  172.      *
  173.      * @param fromIndex the lower-bound (inclusive) of the sub-interval
  174.      * @param size the size of the sub-range
  175.      * @param length the upper-bound (exclusive) of the range
  176.      * @throws IndexOutOfBoundsException if the sub-range is out of bounds
  177.      */
  178.     static void validateFromIndexSize(int fromIndex, int size, int length) {
  179.         // check for any negatives (assume 'length' is positive array length),
  180.         // or overflow safe length check given the values are all positive
  181.         // remaining = length - fromIndex
  182.         if ((fromIndex | size) < 0 || size > length - fromIndex) {
  183.             throw new IndexOutOfBoundsException(
  184.                 // Note: %<d is 'relative indexing' to re-use the last argument
  185.                 String.format("Range [%d, %<d + %d) out of bounds for length %d",
  186.                     fromIndex, size, length));
  187.         }
  188.     }

  189.     /**
  190.      * Generates random bytes and places them into a user-supplied array.
  191.      *
  192.      * <p>The array is filled with bytes extracted from random {@code long} values. This
  193.      * implies that the number of random bytes generated may be larger than the length of
  194.      * the byte array.
  195.      *
  196.      * @param source Source of randomness.
  197.      * @param bytes Array in which to put the generated bytes. Cannot be null.
  198.      * @param start Index at which to start inserting the generated bytes.
  199.      * @param len Number of bytes to insert.
  200.      */
  201.     static void nextBytes(UniformRandomProvider source,
  202.                           byte[] bytes, int start, int len) {
  203.         // Index of first insertion plus multiple of 8 part of length
  204.         // (i.e. length with 3 least significant bits unset).
  205.         final int indexLoopLimit = start + (len & 0x7ffffff8);

  206.         // Start filling in the byte array, 8 bytes at a time.
  207.         int index = start;
  208.         while (index < indexLoopLimit) {
  209.             final long random = source.nextLong();
  210.             bytes[index++] = (byte) random;
  211.             bytes[index++] = (byte) (random >>> 8);
  212.             bytes[index++] = (byte) (random >>> 16);
  213.             bytes[index++] = (byte) (random >>> 24);
  214.             bytes[index++] = (byte) (random >>> 32);
  215.             bytes[index++] = (byte) (random >>> 40);
  216.             bytes[index++] = (byte) (random >>> 48);
  217.             bytes[index++] = (byte) (random >>> 56);
  218.         }

  219.         // Index of last insertion + 1
  220.         final int indexLimit = start + len;

  221.         // Fill in the remaining bytes.
  222.         if (index < indexLimit) {
  223.             long random = source.nextLong();
  224.             for (;;) {
  225.                 bytes[index++] = (byte) random;
  226.                 if (index == indexLimit) {
  227.                     break;
  228.                 }
  229.                 random >>>= 8;
  230.             }
  231.         }
  232.     }

  233.     /**
  234.      * Generates an {@code int} value between 0 (inclusive) and the specified value
  235.      * (exclusive).
  236.      *
  237.      * @param source Source of randomness.
  238.      * @param n Bound on the random number to be returned. Must be strictly positive.
  239.      * @return a random {@code int} value between 0 (inclusive) and {@code n} (exclusive).
  240.      */
  241.     static int nextInt(UniformRandomProvider source,
  242.                        int n) {
  243.         // Lemire (2019): Fast Random Integer Generation in an Interval
  244.         // https://arxiv.org/abs/1805.10941
  245.         long m = (source.nextInt() & 0xffffffffL) * n;
  246.         long l = m & 0xffffffffL;
  247.         if (l < n) {
  248.             // 2^32 % n
  249.             final long t = POW_32 % n;
  250.             while (l < t) {
  251.                 m = (source.nextInt() & 0xffffffffL) * n;
  252.                 l = m & 0xffffffffL;
  253.             }
  254.         }
  255.         return (int) (m >>> 32);
  256.     }

  257.     /**
  258.      * Generates an {@code int} value between the specified {@code origin} (inclusive) and
  259.      * the specified {@code bound} (exclusive).
  260.      *
  261.      * @param source Source of randomness.
  262.      * @param origin Lower bound on the random number to be returned.
  263.      * @param bound Upper bound (exclusive) on the random number to be returned. Must be
  264.      * above {@code origin}.
  265.      * @return a random {@code int} value between {@code origin} (inclusive) and
  266.      * {@code bound} (exclusive).
  267.      */
  268.     static int nextInt(UniformRandomProvider source,
  269.                        int origin, int bound) {
  270.         final int n = bound - origin;
  271.         if (n > 0) {
  272.             return nextInt(source, n) + origin;
  273.         }
  274.         // Range too large to fit in a positive integer.
  275.         // Use simple rejection.
  276.         int v = source.nextInt();
  277.         while (v < origin || v >= bound) {
  278.             v = source.nextInt();
  279.         }
  280.         return v;
  281.     }

  282.     /**
  283.      * Generates an {@code long} value between 0 (inclusive) and the specified value
  284.      * (exclusive).
  285.      *
  286.      * @param source Source of randomness.
  287.      * @param n Bound on the random number to be returned. Must be strictly positive.
  288.      * @return a random {@code long} value between 0 (inclusive) and {@code n}
  289.      * (exclusive).
  290.      */
  291.     static long nextLong(UniformRandomProvider source,
  292.                          long n) {
  293.         long bits;
  294.         long val;
  295.         do {
  296.             bits = source.nextLong() >>> 1;
  297.             val  = bits % n;
  298.         } while (bits - val + (n - 1) < 0);

  299.         return val;
  300.     }

  301.     /**
  302.      * Generates a {@code long} value between the specified {@code origin} (inclusive) and
  303.      * the specified {@code bound} (exclusive).
  304.      *
  305.      * @param source Source of randomness.
  306.      * @param origin Lower bound on the random number to be returned.
  307.      * @param bound Upper bound (exclusive) on the random number to be returned. Must be
  308.      * above {@code origin}.
  309.      * @return a random {@code long} value between {@code origin} (inclusive) and
  310.      * {@code bound} (exclusive).
  311.      */
  312.     static long nextLong(UniformRandomProvider source,
  313.                          long origin, long bound) {
  314.         final long n = bound - origin;
  315.         if (n > 0) {
  316.             return nextLong(source, n) + origin;
  317.         }
  318.         // Range too large to fit in a positive integer.
  319.         // Use simple rejection.
  320.         long v = source.nextLong();
  321.         while (v < origin || v >= bound) {
  322.             v = source.nextLong();
  323.         }
  324.         return v;
  325.     }

  326.     /**
  327.      * Generates a {@code float} value between 0 (inclusive) and the specified value
  328.      * (exclusive).
  329.      *
  330.      * @param source Source of randomness.
  331.      * @param bound Bound on the random number to be returned. Must be strictly positive.
  332.      * @return a random {@code float} value between 0 (inclusive) and {@code bound}
  333.      * (exclusive).
  334.      */
  335.     static float nextFloat(UniformRandomProvider source,
  336.                            float bound) {
  337.         float v = source.nextFloat() * bound;
  338.         if (v >= bound) {
  339.             // Correct rounding
  340.             v = Math.nextDown(bound);
  341.         }
  342.         return v;
  343.     }

  344.     /**
  345.      * Generates a {@code float} value between the specified {@code origin} (inclusive)
  346.      * and the specified {@code bound} (exclusive).
  347.      *
  348.      * @param source Source of randomness.
  349.      * @param origin Lower bound on the random number to be returned. Must be finite.
  350.      * @param bound Upper bound (exclusive) on the random number to be returned. Must be
  351.      * above {@code origin} and finite.
  352.      * @return a random {@code float} value between {@code origin} (inclusive) and
  353.      * {@code bound} (exclusive).
  354.      */
  355.     static float nextFloat(UniformRandomProvider source,
  356.                            float origin, float bound) {
  357.         float v = source.nextFloat();
  358.         // This expression allows (bound - origin) to be infinite
  359.         // origin + (bound - origin) * v
  360.         // == origin - origin * v + bound * v
  361.         v = (1f - v) * origin + v * bound;
  362.         if (v >= bound) {
  363.             // Correct rounding
  364.             v = Math.nextDown(bound);
  365.         }
  366.         return v;
  367.     }

  368.     /**
  369.      * Generates a {@code double} value between 0 (inclusive) and the specified value
  370.      * (exclusive).
  371.      *
  372.      * @param source Source of randomness.
  373.      * @param bound Bound on the random number to be returned. Must be strictly positive.
  374.      * @return a random {@code double} value between 0 (inclusive) and {@code bound}
  375.      * (exclusive).
  376.      */
  377.     static double nextDouble(UniformRandomProvider source,
  378.                              double bound) {
  379.         double v = source.nextDouble() * bound;
  380.         if (v >= bound) {
  381.             // Correct rounding
  382.             v = Math.nextDown(bound);
  383.         }
  384.         return v;
  385.     }

  386.     /**
  387.      * Generates a {@code double} value between the specified {@code origin} (inclusive)
  388.      * and the specified {@code bound} (exclusive).
  389.      *
  390.      * @param source Source of randomness.
  391.      * @param origin Lower bound on the random number to be returned. Must be finite.
  392.      * @param bound Upper bound (exclusive) on the random number to be returned. Must be
  393.      * above {@code origin} and finite.
  394.      * @return a random {@code double} value between {@code origin} (inclusive) and
  395.      * {@code bound} (exclusive).
  396.      */
  397.     static double nextDouble(UniformRandomProvider source,
  398.                              double origin, double bound) {
  399.         double v = source.nextDouble();
  400.         // This expression allows (bound - origin) to be infinite
  401.         // origin + (bound - origin) * v
  402.         // == origin - origin * v + bound * v
  403.         v = (1f - v) * origin + v * bound;
  404.         if (v >= bound) {
  405.             // Correct rounding
  406.             v = Math.nextDown(bound);
  407.         }
  408.         return v;
  409.     }

  410.     // Spliterator support

  411.     /**
  412.      * Base class for spliterators for streams of values. Contains the range current position and
  413.      * end position. Splitting is expected to divide the range in half and create instances
  414.      * that span the two ranges.
  415.      */
  416.     private static class ProviderSpliterator {
  417.         /** The current position in the range. */
  418.         protected long position;
  419.         /** The upper limit of the range. */
  420.         protected final long end;

  421.         /**
  422.          * @param start Start position of the stream (inclusive).
  423.          * @param end Upper limit of the stream (exclusive).
  424.          */
  425.         ProviderSpliterator(long start, long end) {
  426.             position = start;
  427.             this.end = end;
  428.         }

  429.         // Methods required by all Spliterators

  430.         // See Spliterator.estimateSize()
  431.         public long estimateSize() {
  432.             return end - position;
  433.         }

  434.         // See Spliterator.characteristics()
  435.         public int characteristics() {
  436.             return Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.NONNULL | Spliterator.IMMUTABLE;
  437.         }
  438.     }

  439.     /**
  440.      * Spliterator for streams of SplittableUniformRandomProvider.
  441.      */
  442.     static class ProviderSplitsSpliterator extends ProviderSpliterator
  443.             implements Spliterator<SplittableUniformRandomProvider> {
  444.         /** Source of randomness used to initialise the new instances. */
  445.         private final SplittableUniformRandomProvider source;
  446.         /** Generator to split to create new instances. */
  447.         private final SplittableUniformRandomProvider rng;

  448.         /**
  449.          * @param start Start position of the stream (inclusive).
  450.          * @param end Upper limit of the stream (exclusive).
  451.          * @param source Source of randomness used to initialise the new instances.
  452.          * @param rng Generator to split to create new instances.
  453.          */
  454.         ProviderSplitsSpliterator(long start, long end,
  455.                                   SplittableUniformRandomProvider source,
  456.                                   SplittableUniformRandomProvider rng) {
  457.             super(start, end);
  458.             this.source = source;
  459.             this.rng = rng;
  460.         }

  461.         @Override
  462.         public Spliterator<SplittableUniformRandomProvider> trySplit() {
  463.             final long start = position;
  464.             final long middle = (start + end) >>> 1;
  465.             if (middle <= start) {
  466.                 return null;
  467.             }
  468.             position = middle;
  469.             return new ProviderSplitsSpliterator(start, middle, source.split(), rng);
  470.         }

  471.         @Override
  472.         public boolean tryAdvance(Consumer<? super SplittableUniformRandomProvider> action) {
  473.             Objects.requireNonNull(action, NULL_ACTION);
  474.             final long pos = position;
  475.             if (pos < end) {
  476.                 // Advance before exceptions from the action are relayed to the caller
  477.                 position = pos + 1;
  478.                 action.accept(rng.split(source));
  479.                 return true;
  480.             }
  481.             return false;
  482.         }

  483.         @Override
  484.         public void forEachRemaining(Consumer<? super SplittableUniformRandomProvider> action) {
  485.             Objects.requireNonNull(action, NULL_ACTION);
  486.             long pos = position;
  487.             final long last = end;
  488.             if (pos < last) {
  489.                 // Ensure forEachRemaining is called only once
  490.                 position = last;
  491.                 final SplittableUniformRandomProvider s = source;
  492.                 final SplittableUniformRandomProvider r = rng;
  493.                 do {
  494.                     action.accept(r.split(s));
  495.                 } while (++pos < last);
  496.             }
  497.         }
  498.     }

  499.     /**
  500.      * Spliterator for streams of int values that may be recursively split.
  501.      */
  502.     static class ProviderIntsSpliterator extends ProviderSpliterator
  503.             implements Spliterator.OfInt {
  504.         /** Source of randomness. */
  505.         private final SplittableUniformRandomProvider source;
  506.         /** Value generator function. */
  507.         private final ToIntFunction<SplittableUniformRandomProvider> gen;

  508.         /**
  509.          * @param start Start position of the stream (inclusive).
  510.          * @param end Upper limit of the stream (exclusive).
  511.          * @param source Source of randomness.
  512.          * @param gen Value generator function.
  513.          */
  514.         ProviderIntsSpliterator(long start, long end,
  515.                                 SplittableUniformRandomProvider source,
  516.                                 ToIntFunction<SplittableUniformRandomProvider> gen) {
  517.             super(start, end);
  518.             this.source = source;
  519.             this.gen = gen;
  520.         }

  521.         @Override
  522.         public Spliterator.OfInt trySplit() {
  523.             final long start = position;
  524.             final long middle = (start + end) >>> 1;
  525.             if (middle <= start) {
  526.                 return null;
  527.             }
  528.             position = middle;
  529.             return new ProviderIntsSpliterator(start, middle, source.split(), gen);
  530.         }

  531.         @Override
  532.         public boolean tryAdvance(IntConsumer action) {
  533.             Objects.requireNonNull(action, NULL_ACTION);
  534.             final long pos = position;
  535.             if (pos < end) {
  536.                 // Advance before exceptions from the action are relayed to the caller
  537.                 position = pos + 1;
  538.                 action.accept(gen.applyAsInt(source));
  539.                 return true;
  540.             }
  541.             return false;
  542.         }

  543.         @Override
  544.         public void forEachRemaining(IntConsumer action) {
  545.             Objects.requireNonNull(action, NULL_ACTION);
  546.             long pos = position;
  547.             final long last = end;
  548.             if (pos < last) {
  549.                 // Ensure forEachRemaining is called only once
  550.                 position = last;
  551.                 final SplittableUniformRandomProvider s = source;
  552.                 final ToIntFunction<SplittableUniformRandomProvider> g = gen;
  553.                 do {
  554.                     action.accept(g.applyAsInt(s));
  555.                 } while (++pos < last);
  556.             }
  557.         }
  558.     }

  559.     /**
  560.      * Spliterator for streams of long values that may be recursively split.
  561.      */
  562.     static class ProviderLongsSpliterator extends ProviderSpliterator
  563.             implements Spliterator.OfLong {
  564.         /** Source of randomness. */
  565.         private final SplittableUniformRandomProvider source;
  566.         /** Value generator function. */
  567.         private final ToLongFunction<SplittableUniformRandomProvider> gen;

  568.         /**
  569.          * @param start Start position of the stream (inclusive).
  570.          * @param end Upper limit of the stream (exclusive).
  571.          * @param source Source of randomness.
  572.          * @param gen Value generator function.
  573.          */
  574.         ProviderLongsSpliterator(long start, long end,
  575.                                 SplittableUniformRandomProvider source,
  576.                                 ToLongFunction<SplittableUniformRandomProvider> gen) {
  577.             super(start, end);
  578.             this.source = source;
  579.             this.gen = gen;
  580.         }

  581.         @Override
  582.         public Spliterator.OfLong trySplit() {
  583.             final long start = position;
  584.             final long middle = (start + end) >>> 1;
  585.             if (middle <= start) {
  586.                 return null;
  587.             }
  588.             position = middle;
  589.             return new ProviderLongsSpliterator(start, middle, source.split(), gen);
  590.         }

  591.         @Override
  592.         public boolean tryAdvance(LongConsumer action) {
  593.             Objects.requireNonNull(action, NULL_ACTION);
  594.             final long pos = position;
  595.             if (pos < end) {
  596.                 // Advance before exceptions from the action are relayed to the caller
  597.                 position = pos + 1;
  598.                 action.accept(gen.applyAsLong(source));
  599.                 return true;
  600.             }
  601.             return false;
  602.         }

  603.         @Override
  604.         public void forEachRemaining(LongConsumer action) {
  605.             Objects.requireNonNull(action, NULL_ACTION);
  606.             long pos = position;
  607.             final long last = end;
  608.             if (pos < last) {
  609.                 // Ensure forEachRemaining is called only once
  610.                 position = last;
  611.                 final SplittableUniformRandomProvider s = source;
  612.                 final ToLongFunction<SplittableUniformRandomProvider> g = gen;
  613.                 do {
  614.                     action.accept(g.applyAsLong(s));
  615.                 } while (++pos < last);
  616.             }
  617.         }
  618.     }

  619.     /**
  620.      * Spliterator for streams of double values that may be recursively split.
  621.      */
  622.     static class ProviderDoublesSpliterator extends ProviderSpliterator
  623.             implements Spliterator.OfDouble {
  624.         /** Source of randomness. */
  625.         private final SplittableUniformRandomProvider source;
  626.         /** Value generator function. */
  627.         private final ToDoubleFunction<SplittableUniformRandomProvider> gen;

  628.         /**
  629.          * @param start Start position of the stream (inclusive).
  630.          * @param end Upper limit of the stream (exclusive).
  631.          * @param source Source of randomness.
  632.          * @param gen Value generator function.
  633.          */
  634.         ProviderDoublesSpliterator(long start, long end,
  635.                                 SplittableUniformRandomProvider source,
  636.                                 ToDoubleFunction<SplittableUniformRandomProvider> gen) {
  637.             super(start, end);
  638.             this.source = source;
  639.             this.gen = gen;
  640.         }

  641.         @Override
  642.         public Spliterator.OfDouble trySplit() {
  643.             final long start = position;
  644.             final long middle = (start + end) >>> 1;
  645.             if (middle <= start) {
  646.                 return null;
  647.             }
  648.             position = middle;
  649.             return new ProviderDoublesSpliterator(start, middle, source.split(), gen);
  650.         }

  651.         @Override
  652.         public boolean tryAdvance(DoubleConsumer action) {
  653.             Objects.requireNonNull(action, NULL_ACTION);
  654.             final long pos = position;
  655.             if (pos < end) {
  656.                 // Advance before exceptions from the action are relayed to the caller
  657.                 position = pos + 1;
  658.                 action.accept(gen.applyAsDouble(source));
  659.                 return true;
  660.             }
  661.             return false;
  662.         }

  663.         @Override
  664.         public void forEachRemaining(DoubleConsumer action) {
  665.             Objects.requireNonNull(action, NULL_ACTION);
  666.             long pos = position;
  667.             final long last = end;
  668.             if (pos < last) {
  669.                 // Ensure forEachRemaining is called only once
  670.                 position = last;
  671.                 final SplittableUniformRandomProvider s = source;
  672.                 final ToDoubleFunction<SplittableUniformRandomProvider> g = gen;
  673.                 do {
  674.                     action.accept(g.applyAsDouble(s));
  675.                 } while (++pos < last);
  676.             }
  677.         }
  678.     }
  679. }