You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2019/09/03 08:43:36 UTC
[commons-rng] 01/04: RNG-115: Fix JDKRandom to restore state to a
new instance.
This is an automated email from the ASF dual-hosted git repository.
aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-rng.git
commit 592ad0be4fe4fa912b5cdaf5f83b006eb8a02f77
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Mon Sep 2 21:42:12 2019 +0100
RNG-115: Fix JDKRandom to restore state to a new instance.
Save the state size to the byte array representation. This can be read
by any instance when restoring.
---
.../commons/rng/core/source32/JDKRandom.java | 19 ++++++++++----
.../commons/rng/core/source32/JDKRandomTest.java | 29 ++++++++++++++++++++++
2 files changed, 43 insertions(+), 5 deletions(-)
diff --git a/commons-rng-core/src/main/java/org/apache/commons/rng/core/source32/JDKRandom.java b/commons-rng-core/src/main/java/org/apache/commons/rng/core/source32/JDKRandom.java
index 94ba0b4..e9245b1 100644
--- a/commons-rng-core/src/main/java/org/apache/commons/rng/core/source32/JDKRandom.java
+++ b/commons-rng-core/src/main/java/org/apache/commons/rng/core/source32/JDKRandom.java
@@ -21,6 +21,9 @@ import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.ByteArrayOutputStream;
+
+import org.apache.commons.rng.core.util.NumberFactory;
+
import java.io.ByteArrayInputStream;
/**
@@ -42,8 +45,6 @@ import java.io.ByteArrayInputStream;
public class JDKRandom extends IntProvider {
/** Delegate. Cannot be "final" (to allow serialization). */
private Random delegate;
- /** Size of the byte representation of the state (of the delegate). */
- private int stateSize;
/**
* Creates an instance with the given seed.
@@ -75,8 +76,11 @@ public class JDKRandom extends IntProvider {
oos.writeObject(delegate);
final byte[] state = bos.toByteArray();
- stateSize = state.length; // To allow state recovery.
- return composeStateInternal(state,
+ final int stateSize = state.length; // To allow state recovery.
+ // Compose the size with the state
+ final byte[] sizeAndState = composeStateInternal(NumberFactory.makeByteArray(stateSize),
+ state);
+ return composeStateInternal(sizeAndState,
super.getStateInternal());
} catch (IOException e) {
// Workaround checked exception.
@@ -87,7 +91,12 @@ public class JDKRandom extends IntProvider {
/** {@inheritDoc} */
@Override
protected void setStateInternal(byte[] s) {
- final byte[][] c = splitStateInternal(s, stateSize);
+ // First obtain the state size
+ final byte[][] s2 = splitStateInternal(s, 4);
+ final int stateSize = NumberFactory.makeInt(s2[0]);
+
+ // Second obtain the state
+ final byte[][] c = splitStateInternal(s2[1], stateSize);
try {
final ByteArrayInputStream bis = new ByteArrayInputStream(c[0]);
diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/JDKRandomTest.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/JDKRandomTest.java
index 73be52e..0e86baf 100644
--- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/JDKRandomTest.java
+++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/JDKRandomTest.java
@@ -18,6 +18,7 @@ package org.apache.commons.rng.core.source32;
import java.util.Random;
+import org.apache.commons.rng.RandomProviderState;
import org.junit.Assert;
import org.junit.Test;
@@ -35,4 +36,32 @@ public class JDKRandomTest {
Assert.assertEquals(r + " nextInt", jdk.nextInt(), rng.nextInt());
}
}
+
+ /**
+ * Test the state can be used to restore a new instance that has not previously had a call
+ * to save the state.
+ */
+ @Test
+ public void testRestoreToNewInstance() {
+ final long seed = 8796746234L;
+ final JDKRandom rng1 = new JDKRandom(seed);
+ final JDKRandom rng2 = new JDKRandom(seed + 1);
+
+ // Ensure different
+ final int numRepeats = 10;
+ for (int r = 0; r < numRepeats; r++) {
+ Assert.assertNotEquals(r + " nextInt", rng1.nextInt(), rng2.nextInt());
+ }
+
+ final RandomProviderState state = rng1.saveState();
+ // This second instance will not know the state size required to write
+ // java.util.Random to serialized form. This is only known when the saveState
+ // method is called.
+ rng2.restoreState(state);
+
+ // Ensure the same
+ for (int r = 0; r < numRepeats; r++) {
+ Assert.assertEquals(r + " nextInt", rng1.nextInt(), rng2.nextInt());
+ }
+ }
}