|
1 /* |
|
2 * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. |
|
3 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. |
|
4 * |
|
5 * |
|
6 * |
|
7 * |
|
8 * |
|
9 * |
|
10 * |
|
11 * |
|
12 * |
|
13 * |
|
14 * |
|
15 * |
|
16 * |
|
17 * |
|
18 * |
|
19 * |
|
20 * |
|
21 * |
|
22 * |
|
23 * |
|
24 */ |
|
25 |
|
26 // package java.util; |
|
27 |
|
28 import java.util.Spliterator; |
|
29 import java.util.function.Consumer; |
|
30 import java.util.function.IntConsumer; |
|
31 import java.util.function.LongConsumer; |
|
32 import java.util.function.DoubleConsumer; |
|
33 import java.util.stream.StreamSupport; |
|
34 import java.util.stream.Stream; |
|
35 |
|
36 /** |
|
37 * This class provides much of the implementation of the |
|
38 * {@code ArbitrarilyJumpableRng} interface, to minimize the effort |
|
39 * required to implement that interface. |
|
40 * |
|
41 * To implement a pseudorandom number generator, the programmer needs |
|
42 * only to extend this class and provide implementations for the |
|
43 * methods {@code nextInt()}, {@code nextLong()}, {@code copy()}, |
|
44 * {@code jump(distance)}, {@code jumpPowerOfTwo(distance)}, |
|
45 * {@code defaultJumpDistance()}, and {@code defaultLeapDistance()}. |
|
46 * |
|
47 * (If the pseudorandom number generator also has the ability to split, |
|
48 * then the programmer may wish to consider instead extending |
|
49 * {@code AbstractSplittableArbitrarilyJumpableRng}.) |
|
50 * |
|
51 * The programmer should generally provide at least three constructors: |
|
52 * one that takes no arguments, one that accepts a {@code long} |
|
53 * seed value, and one that accepts an array of seed {@code byte} values. |
|
54 * This class provides a public {@code initialSeed()} method that may |
|
55 * be useful in initializing some static state from which to derive |
|
56 * defaults seeds for use by the no-argument constructor. |
|
57 * |
|
58 * For the stream methods (such as {@code ints()} and {@code splits()}), |
|
59 * this class provides {@code Spliterator}-based implementations that |
|
60 * allow parallel execution when appropriate. In this respect |
|
61 * {@code ArbitrarilyJumpableRng} differs from {@code JumpableRng}, |
|
62 * which provides very simple implementations that produce |
|
63 * sequential streams only. |
|
64 * |
|
65 * <p>An implementation of the {@code AbstractArbitrarilyJumpableRng} class |
|
66 * must provide concrete definitions for the methods {@code nextInt()}, |
|
67 * {@code nextLong}, {@code period()}, {@code copy()}, {@code jump(double)}, |
|
68 * {@code defaultJumpDistance()}, and {@code defaultLeapDistance()}. |
|
69 * Default implementations are provided for all other methods. |
|
70 * |
|
71 * The documentation for each non-abstract method in this class |
|
72 * describes its implementation in detail. Each of these methods may |
|
73 * be overridden if the pseudorandom number generator being |
|
74 * implemented admits a more efficient implementation. |
|
75 * |
|
76 * @author Guy Steele |
|
77 * @since 1.9 |
|
78 */ |
|
79 public abstract class AbstractArbitrarilyJumpableRng |
|
80 extends AbstractSpliteratorRng implements ArbitrarilyJumpableRng { |
|
81 |
|
82 /* |
|
83 * Implementation Overview. |
|
84 * |
|
85 * This class provides most of the "user API" methods needed to satisfy |
|
86 * the interface java.util.ArbitrarilyJumpableRng. Most of these methods |
|
87 * are in turn inherited from AbstractRng and the non-public class |
|
88 * AbstractSpliteratorRng; this file implements four versions of the |
|
89 * jumps method and defines the spliterators necessary to support them. |
|
90 * |
|
91 * File organization: First the non-public methods needed by the class |
|
92 * AbstractSpliteratorRng, then the main public methods, followed by some |
|
93 * custom spliterator classes needed for stream methods. |
|
94 */ |
|
95 |
|
96 // IllegalArgumentException messages |
|
97 static final String BadLogDistance = "logDistance must be non-negative"; |
|
98 |
|
99 // Methods required by class AbstractSpliteratorRng |
|
100 Spliterator.OfInt makeIntsSpliterator(long index, long fence, int origin, int bound) { |
|
101 return new RandomIntsSpliterator(this, index, fence, origin, bound); |
|
102 } |
|
103 Spliterator.OfLong makeLongsSpliterator(long index, long fence, long origin, long bound) { |
|
104 return new RandomLongsSpliterator(this, index, fence, origin, bound); |
|
105 } |
|
106 Spliterator.OfDouble makeDoublesSpliterator(long index, long fence, double origin, double bound) { |
|
107 return new RandomDoublesSpliterator(this, index, fence, origin, bound); |
|
108 } |
|
109 |
|
110 // Similar methods used by this class |
|
111 Spliterator<Rng> makeJumpsSpliterator(long index, long fence, double distance) { |
|
112 return new RandomJumpsSpliterator(this, index, fence, distance); |
|
113 } |
|
114 Spliterator<JumpableRng> makeLeapsSpliterator(long index, long fence, double distance) { |
|
115 return new RandomLeapsSpliterator(this, index, fence, distance); |
|
116 } |
|
117 Spliterator<ArbitrarilyJumpableRng> makeArbitraryJumpsSpliterator(long index, long fence, double distance) { |
|
118 return new RandomArbitraryJumpsSpliterator(this, index, fence, distance); |
|
119 } |
|
120 |
|
121 /* ---------------- public methods ---------------- */ |
|
122 |
|
123 /** |
|
124 * Returns a new generator whose internal state is an exact copy |
|
125 * of this generator (therefore their future behavior should be |
|
126 * identical if subjected to the same series of operations). |
|
127 * |
|
128 * @return a new object that is a copy of this generator |
|
129 */ |
|
130 public abstract AbstractArbitrarilyJumpableRng copy(); |
|
131 |
|
132 // Stream methods for jumping |
|
133 |
|
134 /** |
|
135 * Returns an effectively unlimited stream of new pseudorandom |
|
136 * number generators, each of which implements the {@code Rng} |
|
137 * interface, produced by jumping copies of this generator |
|
138 * by different integer multiples of the default jump distance. |
|
139 * |
|
140 * @implNote This method is implemented to be equivalent to |
|
141 * {@code jumps(Long.MAX_VALUE)}. |
|
142 * |
|
143 * @return a stream of objects that implement the {@code Rng} interface |
|
144 */ |
|
145 public Stream<Rng> jumps() { |
|
146 return StreamSupport.stream |
|
147 (makeJumpsSpliterator(0L, Long.MAX_VALUE, defaultJumpDistance()), |
|
148 false); |
|
149 } |
|
150 |
|
151 /** |
|
152 * Returns a stream producing the given {@code streamSize} number of |
|
153 * new pseudorandom number generators, each of which implements the |
|
154 * {@code Rng} interface, produced by jumping copies of this generator |
|
155 * by different integer multiples of the default jump distance. |
|
156 * |
|
157 * @param streamSize the number of generators to generate |
|
158 * @return a stream of objects that implement the {@code Rng} interface |
|
159 * @throws IllegalArgumentException if {@code streamSize} is |
|
160 * less than zero |
|
161 */ |
|
162 public Stream<Rng> jumps(long streamSize) { |
|
163 return StreamSupport.stream |
|
164 (makeJumpsSpliterator(0L, streamSize, defaultJumpDistance()), |
|
165 false); |
|
166 } |
|
167 |
|
168 /** |
|
169 * Returns an effectively unlimited stream of new pseudorandom |
|
170 * number generators, each of which implements the {@code Rng} |
|
171 * interface, produced by jumping copies of this generator |
|
172 * by different integer multiples of the specified jump distance. |
|
173 * |
|
174 * @implNote This method is implemented to be equivalent to |
|
175 * {@code jumps(Long.MAX_VALUE)}. |
|
176 * |
|
177 * @param distance a distance to jump forward within the state cycle |
|
178 * @return a stream of objects that implement the {@code Rng} interface |
|
179 */ |
|
180 public Stream<ArbitrarilyJumpableRng> jumps(double distance) { |
|
181 return StreamSupport.stream |
|
182 (makeArbitraryJumpsSpliterator(0L, Long.MAX_VALUE, distance), |
|
183 false); |
|
184 } |
|
185 |
|
186 /** |
|
187 * Returns a stream producing the given {@code streamSize} number of |
|
188 * new pseudorandom number generators, each of which implements the |
|
189 * {@code Rng} interface, produced by jumping copies of this generator |
|
190 * by different integer multiples of the specified jump distance. |
|
191 * |
|
192 * @param streamSize the number of generators to generate |
|
193 * @param distance a distance to jump forward within the state cycle |
|
194 * @return a stream of objects that implement the {@code Rng} interface |
|
195 * @throws IllegalArgumentException if {@code streamSize} is |
|
196 * less than zero |
|
197 */ |
|
198 public Stream<ArbitrarilyJumpableRng> jumps(long streamSize, double distance) { |
|
199 RngSupport.checkStreamSize(streamSize); |
|
200 return StreamSupport.stream |
|
201 (makeArbitraryJumpsSpliterator(0L, streamSize, distance), |
|
202 false); |
|
203 } |
|
204 |
|
205 /** |
|
206 * Alter the state of this pseudorandom number generator so as to |
|
207 * jump forward a very large, fixed distance (typically 2<sup>128</sup> |
|
208 * or more) within its state cycle. The distance used is that |
|
209 * returned by method {@code defaultLeapDistance()}. |
|
210 */ |
|
211 public void leap() { jump(defaultLeapDistance()); } |
|
212 |
|
213 // Stream methods for leaping |
|
214 |
|
215 /** |
|
216 * Returns an effectively unlimited stream of new pseudorandom |
|
217 * number generators, each of which implements the {@code Rng} |
|
218 * interface, produced by jumping copies of this generator |
|
219 * by different integer multiples of the default leap distance. |
|
220 * |
|
221 * @implNote This method is implemented to be equivalent to |
|
222 * {@code leaps(Long.MAX_VALUE)}. |
|
223 * |
|
224 * @return a stream of objects that implement the {@code Rng} interface |
|
225 */ |
|
226 public Stream<JumpableRng> leaps() { |
|
227 return StreamSupport.stream |
|
228 (makeLeapsSpliterator(0L, Long.MAX_VALUE, defaultLeapDistance()), |
|
229 false); |
|
230 } |
|
231 |
|
232 /** |
|
233 * Returns a stream producing the given {@code streamSize} number of |
|
234 * new pseudorandom number generators, each of which implements the |
|
235 * {@code Rng} interface, produced by jumping copies of this generator |
|
236 * by different integer multiples of the default leap distance. |
|
237 * |
|
238 * @param streamSize the number of generators to generate |
|
239 * @return a stream of objects that implement the {@code Rng} interface |
|
240 * @throws IllegalArgumentException if {@code streamSize} is |
|
241 * less than zero |
|
242 */ |
|
243 public Stream<JumpableRng> leaps(long streamSize) { |
|
244 return StreamSupport.stream |
|
245 (makeLeapsSpliterator(0L, streamSize, defaultLeapDistance()), |
|
246 false); |
|
247 } |
|
248 |
|
249 |
|
250 /** |
|
251 * Spliterator for int streams. We multiplex the four int |
|
252 * versions into one class by treating a bound less than origin as |
|
253 * unbounded, and also by treating "infinite" as equivalent to |
|
254 * Long.MAX_VALUE. For splits, we choose to override the method |
|
255 * {@code trySplit()} to try to optimize execution speed: instead of |
|
256 * dividing a range in half, it breaks off the largest possible chunk |
|
257 * whose size is a power of two such that the remaining chunk is not |
|
258 * empty. In this way, the necessary jump distances will tend to be |
|
259 * powers of two. The long and double versions of this class are |
|
260 * identical except for types. |
|
261 */ |
|
262 static class RandomIntsSpliterator extends RngSupport.RandomSpliterator implements Spliterator.OfInt { |
|
263 final ArbitrarilyJumpableRng generatingRng; |
|
264 final int origin; |
|
265 final int bound; |
|
266 |
|
267 RandomIntsSpliterator(ArbitrarilyJumpableRng generatingRng, long index, long fence, int origin, int bound) { |
|
268 super(index, fence); |
|
269 this.origin = origin; this.bound = bound; |
|
270 this.generatingRng = generatingRng; |
|
271 } |
|
272 |
|
273 public Spliterator.OfInt trySplit() { |
|
274 long i = index, delta = Long.highestOneBit((fence - i) - 1), m = i + delta; |
|
275 if (m <= i) return null; |
|
276 index = m; |
|
277 ArbitrarilyJumpableRng r = (ArbitrarilyJumpableRng) generatingRng; |
|
278 return new RandomIntsSpliterator(r.copyAndJump((double)delta), i, m, origin, bound); |
|
279 } |
|
280 |
|
281 public boolean tryAdvance(IntConsumer consumer) { |
|
282 if (consumer == null) throw new NullPointerException(); |
|
283 long i = index, f = fence; |
|
284 if (i < f) { |
|
285 consumer.accept(RngSupport.boundedNextInt(generatingRng, origin, bound)); |
|
286 index = i + 1; |
|
287 return true; |
|
288 } |
|
289 else return false; |
|
290 } |
|
291 |
|
292 public void forEachRemaining(IntConsumer consumer) { |
|
293 if (consumer == null) throw new NullPointerException(); |
|
294 long i = index, f = fence; |
|
295 if (i < f) { |
|
296 index = f; |
|
297 ArbitrarilyJumpableRng r = generatingRng; |
|
298 int o = origin, b = bound; |
|
299 do { |
|
300 consumer.accept(RngSupport.boundedNextInt(r, o, b)); |
|
301 } while (++i < f); |
|
302 } |
|
303 } |
|
304 } |
|
305 |
|
306 /** |
|
307 * Spliterator for long streams. |
|
308 */ |
|
309 static class RandomLongsSpliterator extends RngSupport.RandomSpliterator implements Spliterator.OfLong { |
|
310 final ArbitrarilyJumpableRng generatingRng; |
|
311 final long origin; |
|
312 final long bound; |
|
313 |
|
314 RandomLongsSpliterator(ArbitrarilyJumpableRng generatingRng, long index, long fence, long origin, long bound) { |
|
315 super(index, fence); |
|
316 this.generatingRng = generatingRng; |
|
317 this.origin = origin; this.bound = bound; |
|
318 } |
|
319 |
|
320 public Spliterator.OfLong trySplit() { |
|
321 long i = index, delta = Long.highestOneBit((fence - i) - 1), m = i + delta; |
|
322 if (m <= i) return null; |
|
323 index = m; |
|
324 ArbitrarilyJumpableRng r = (ArbitrarilyJumpableRng) generatingRng; |
|
325 return new RandomLongsSpliterator(r.copyAndJump((double)delta), i, m, origin, bound); |
|
326 } |
|
327 |
|
328 public boolean tryAdvance(LongConsumer consumer) { |
|
329 if (consumer == null) throw new NullPointerException(); |
|
330 long i = index, f = fence; |
|
331 if (i < f) { |
|
332 consumer.accept(RngSupport.boundedNextLong(generatingRng, origin, bound)); |
|
333 index = i + 1; |
|
334 return true; |
|
335 } |
|
336 else return false; |
|
337 } |
|
338 |
|
339 public void forEachRemaining(LongConsumer consumer) { |
|
340 if (consumer == null) throw new NullPointerException(); |
|
341 long i = index, f = fence; |
|
342 if (i < f) { |
|
343 index = f; |
|
344 ArbitrarilyJumpableRng r = generatingRng; |
|
345 long o = origin, b = bound; |
|
346 do { |
|
347 consumer.accept(RngSupport.boundedNextLong(r, o, b)); |
|
348 } while (++i < f); |
|
349 } |
|
350 } |
|
351 } |
|
352 |
|
353 /** |
|
354 * Spliterator for double streams. |
|
355 */ |
|
356 static class RandomDoublesSpliterator extends RngSupport.RandomSpliterator implements Spliterator.OfDouble { |
|
357 final ArbitrarilyJumpableRng generatingRng; |
|
358 final double origin; |
|
359 final double bound; |
|
360 |
|
361 RandomDoublesSpliterator(ArbitrarilyJumpableRng generatingRng, long index, long fence, double origin, double bound) { |
|
362 super(index, fence); |
|
363 this.generatingRng = generatingRng; |
|
364 this.origin = origin; this.bound = bound; |
|
365 } |
|
366 |
|
367 public Spliterator.OfDouble trySplit() { |
|
368 |
|
369 long i = index, delta = Long.highestOneBit((fence - i) - 1), m = i + delta; |
|
370 if (m <= i) return null; |
|
371 index = m; |
|
372 ArbitrarilyJumpableRng r = (ArbitrarilyJumpableRng) generatingRng; |
|
373 return new RandomDoublesSpliterator(r.copyAndJump((double)delta), i, m, origin, bound); |
|
374 } |
|
375 |
|
376 public boolean tryAdvance(DoubleConsumer consumer) { |
|
377 if (consumer == null) throw new NullPointerException(); |
|
378 long i = index, f = fence; |
|
379 if (i < f) { |
|
380 consumer.accept(RngSupport.boundedNextDouble(generatingRng, origin, bound)); |
|
381 index = i + 1; |
|
382 return true; |
|
383 } |
|
384 else return false; |
|
385 } |
|
386 |
|
387 public void forEachRemaining(DoubleConsumer consumer) { |
|
388 if (consumer == null) throw new NullPointerException(); |
|
389 long i = index, f = fence; |
|
390 if (i < f) { |
|
391 index = f; |
|
392 ArbitrarilyJumpableRng r = generatingRng; |
|
393 double o = origin, b = bound; |
|
394 do { |
|
395 consumer.accept(RngSupport.boundedNextDouble(r, o, b)); |
|
396 } while (++i < f); |
|
397 } |
|
398 } |
|
399 } |
|
400 |
|
401 // Spliterators for producing new generators by jumping or leaping. The |
|
402 // complete implementation of each of these spliterators is right here. |
|
403 // In the same manner as for the preceding spliterators, the method trySplit() is |
|
404 // coded to optimize execution speed: instead of dividing a range |
|
405 // in half, it breaks off the largest possible chunk whose |
|
406 // size is a power of two such that the remaining chunk is not |
|
407 // empty. In this way, the necessary jump distances will tend to be |
|
408 // powers of two. |
|
409 |
|
410 /** |
|
411 * Spliterator for stream of generators of type Rng produced by jumps. |
|
412 */ |
|
413 static class RandomJumpsSpliterator extends RngSupport.RandomSpliterator implements Spliterator<Rng> { |
|
414 ArbitrarilyJumpableRng generatingRng; |
|
415 final double distance; |
|
416 |
|
417 RandomJumpsSpliterator(ArbitrarilyJumpableRng generatingRng, long index, long fence, double distance) { |
|
418 super(index, fence); |
|
419 this.generatingRng = generatingRng; this.distance = distance; |
|
420 } |
|
421 |
|
422 public Spliterator<Rng> trySplit() { |
|
423 long i = index, delta = Long.highestOneBit((fence - i) - 1), m = i + delta; |
|
424 if (m <= i) return null; |
|
425 index = m; |
|
426 ArbitrarilyJumpableRng r = (ArbitrarilyJumpableRng) generatingRng; |
|
427 // Because delta is a power of two, (distance * (double)delta) can always be computed exactly. |
|
428 return new RandomJumpsSpliterator(r.copyAndJump(distance * (double)delta), i, m, distance); |
|
429 } |
|
430 |
|
431 public boolean tryAdvance(Consumer<? super Rng> consumer) { |
|
432 if (consumer == null) throw new NullPointerException(); |
|
433 long i = index, f = fence; |
|
434 if (i < f) { |
|
435 consumer.accept(generatingRng.copyAndJump(distance)); |
|
436 index = i + 1; |
|
437 return true; |
|
438 } |
|
439 return false; |
|
440 } |
|
441 |
|
442 public void forEachRemaining(Consumer<? super Rng> consumer) { |
|
443 if (consumer == null) throw new NullPointerException(); |
|
444 long i = index, f = fence; |
|
445 if (i < f) { |
|
446 index = f; |
|
447 ArbitrarilyJumpableRng r = generatingRng; |
|
448 do { |
|
449 consumer.accept(r.copyAndJump(distance)); |
|
450 } while (++i < f); |
|
451 } |
|
452 } |
|
453 } |
|
454 |
|
455 /** |
|
456 * Spliterator for stream of generators of type Rng produced by leaps. |
|
457 */ |
|
458 static class RandomLeapsSpliterator extends RngSupport.RandomSpliterator implements Spliterator<JumpableRng> { |
|
459 ArbitrarilyJumpableRng generatingRng; |
|
460 final double distance; |
|
461 |
|
462 RandomLeapsSpliterator(ArbitrarilyJumpableRng generatingRng, long index, long fence, double distance) { |
|
463 super(index, fence); |
|
464 this.generatingRng = generatingRng; this.distance = distance; |
|
465 } |
|
466 |
|
467 public Spliterator<JumpableRng> trySplit() { |
|
468 long i = index, delta = Long.highestOneBit((fence - i) - 1), m = i + delta; |
|
469 if (m <= i) return null; |
|
470 index = m; |
|
471 // Because delta is a power of two, (distance * (double)delta) can always be computed exactly. |
|
472 return new RandomLeapsSpliterator(generatingRng.copyAndJump(distance * (double)delta), i, m, distance); |
|
473 } |
|
474 |
|
475 public boolean tryAdvance(Consumer<? super JumpableRng> consumer) { |
|
476 if (consumer == null) throw new NullPointerException(); |
|
477 long i = index, f = fence; |
|
478 if (i < f) { |
|
479 consumer.accept(generatingRng.copyAndJump(distance)); |
|
480 index = i + 1; |
|
481 return true; |
|
482 } |
|
483 return false; |
|
484 } |
|
485 |
|
486 public void forEachRemaining(Consumer<? super JumpableRng> consumer) { |
|
487 if (consumer == null) throw new NullPointerException(); |
|
488 long i = index, f = fence; |
|
489 if (i < f) { |
|
490 index = f; |
|
491 ArbitrarilyJumpableRng r = generatingRng; |
|
492 do { |
|
493 consumer.accept(r.copyAndJump(distance)); |
|
494 } while (++i < f); |
|
495 } |
|
496 } |
|
497 } |
|
498 |
|
499 /** |
|
500 * Spliterator for stream of generators of type Rng produced by arbitrary jumps. |
|
501 */ |
|
502 static class RandomArbitraryJumpsSpliterator extends RngSupport.RandomSpliterator implements Spliterator<ArbitrarilyJumpableRng> { |
|
503 ArbitrarilyJumpableRng generatingRng; |
|
504 final double distance; |
|
505 |
|
506 RandomArbitraryJumpsSpliterator(ArbitrarilyJumpableRng generatingRng, long index, long fence, double distance) { |
|
507 super(index, fence); |
|
508 this.generatingRng = generatingRng; this.distance = distance; |
|
509 } |
|
510 |
|
511 public Spliterator<ArbitrarilyJumpableRng> trySplit() { |
|
512 long i = index, delta = Long.highestOneBit((fence - i) - 1), m = i + delta; |
|
513 if (m <= i) return null; |
|
514 index = m; |
|
515 // Because delta is a power of two, (distance * (double)delta) can always be computed exactly. |
|
516 return new RandomArbitraryJumpsSpliterator(generatingRng.copyAndJump(distance * (double)delta), i, m, distance); |
|
517 } |
|
518 |
|
519 public boolean tryAdvance(Consumer<? super ArbitrarilyJumpableRng> consumer) { |
|
520 if (consumer == null) throw new NullPointerException(); |
|
521 long i = index, f = fence; |
|
522 if (i < f) { |
|
523 consumer.accept(generatingRng.copyAndJump(distance)); |
|
524 index = i + 1; |
|
525 return true; |
|
526 } |
|
527 return false; |
|
528 } |
|
529 |
|
530 public void forEachRemaining(Consumer<? super ArbitrarilyJumpableRng> consumer) { |
|
531 if (consumer == null) throw new NullPointerException(); |
|
532 long i = index, f = fence; |
|
533 if (i < f) { |
|
534 index = f; |
|
535 ArbitrarilyJumpableRng r = generatingRng; |
|
536 do { |
|
537 consumer.accept(r.copyAndJump(distance)); |
|
538 } while (++i < f); |
|
539 } |
|
540 } |
|
541 } |
|
542 |
|
543 } |