Make Random implementations serializable (KT-25571)
Make Random.Default, XorWowRandom, and wrapper classes for JDK Random implement Serializable interface. Co-authored-by: Ilya Gorbunov <ilya.gorbunov@jetbrains.com>
This commit is contained in:
committed by
GitHub
parent
38967f208e
commit
00506a75d3
@@ -88,7 +88,7 @@ public abstract class Random {
|
|||||||
|
|
||||||
public open fun nextLong(from: kotlin.Long, until: kotlin.Long): kotlin.Long
|
public open fun nextLong(from: kotlin.Long, until: kotlin.Long): kotlin.Long
|
||||||
|
|
||||||
public companion object of Random Default : kotlin.random.Random {
|
public companion object of Random Default : kotlin.random.Random, kotlin.io.Serializable {
|
||||||
public open override fun nextBits(bitCount: kotlin.Int): kotlin.Int
|
public open override fun nextBits(bitCount: kotlin.Int): kotlin.Int
|
||||||
|
|
||||||
public open override fun nextBoolean(): kotlin.Boolean
|
public open override fun nextBoolean(): kotlin.Boolean
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public abstract class Random {
|
|||||||
|
|
||||||
public open fun nextLong(from: kotlin.Long, until: kotlin.Long): kotlin.Long
|
public open fun nextLong(from: kotlin.Long, until: kotlin.Long): kotlin.Long
|
||||||
|
|
||||||
public companion object of Random Default : kotlin.random.Random {
|
public companion object of Random Default : kotlin.random.Random, kotlin.io.Serializable {
|
||||||
public open override fun nextBits(bitCount: kotlin.Int): kotlin.Int
|
public open override fun nextBits(bitCount: kotlin.Int): kotlin.Int
|
||||||
|
|
||||||
public open override fun nextBoolean(): kotlin.Boolean
|
public open override fun nextBoolean(): kotlin.Boolean
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
package kotlin.random
|
package kotlin.random
|
||||||
|
|
||||||
import kotlin.UnsupportedOperationException
|
import kotlin.internal.IMPLEMENTATIONS
|
||||||
import kotlin.internal.*
|
import kotlin.internal.InlineOnly
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a [java.util.Random][java.util.Random] instance that uses the specified Kotlin [Random] generator as a randomness source.
|
* Creates a [java.util.Random][java.util.Random] instance that uses the specified Kotlin [Random] generator as a randomness source.
|
||||||
@@ -49,15 +49,18 @@ internal abstract class AbstractPlatformRandom : Random() {
|
|||||||
|
|
||||||
internal class FallbackThreadLocalRandom : AbstractPlatformRandom() {
|
internal class FallbackThreadLocalRandom : AbstractPlatformRandom() {
|
||||||
private val implStorage = object : ThreadLocal<java.util.Random>() {
|
private val implStorage = object : ThreadLocal<java.util.Random>() {
|
||||||
override fun initialValue(): java.util.Random {
|
override fun initialValue(): java.util.Random = java.util.Random()
|
||||||
return java.util.Random()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override val impl: java.util.Random
|
override val impl: java.util.Random
|
||||||
get() = implStorage.get()
|
get() = implStorage.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PlatformRandom(override val impl: java.util.Random) : AbstractPlatformRandom()
|
private class PlatformRandom(override val impl: java.util.Random) : AbstractPlatformRandom(), Serializable {
|
||||||
|
private companion object {
|
||||||
|
private const val serialVersionUID: Long = 0L
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class KotlinRandom(val impl: Random) : java.util.Random() {
|
private class KotlinRandom(val impl: Random) : java.util.Random() {
|
||||||
override fun next(bits: Int): Int = impl.nextBits(bits)
|
override fun next(bits: Int): Int = impl.nextBits(bits)
|
||||||
@@ -73,6 +76,7 @@ private class KotlinRandom(val impl: Random) : java.util.Random() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var seedInitialized: Boolean = false
|
private var seedInitialized: Boolean = false
|
||||||
|
|
||||||
override fun setSeed(seed: Long) {
|
override fun setSeed(seed: Long) {
|
||||||
if (!seedInitialized) {
|
if (!seedInitialized) {
|
||||||
// ignore seed value from constructor
|
// ignore seed value from constructor
|
||||||
@@ -81,4 +85,8 @@ private class KotlinRandom(val impl: Random) : java.util.Random() {
|
|||||||
throw UnsupportedOperationException("Setting seed is not supported.")
|
throw UnsupportedOperationException("Setting seed is not supported.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
private const val serialVersionUID: Long = 0L
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package random
|
||||||
|
|
||||||
|
import test.io.deserializeFromHex
|
||||||
|
import test.io.serializeAndDeserialize
|
||||||
|
import kotlin.random.Random
|
||||||
|
import kotlin.random.asJavaRandom
|
||||||
|
import kotlin.random.asKotlinRandom
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertSame
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class RandomSerializationTest {
|
||||||
|
@Test
|
||||||
|
fun defaultIsSerializable() {
|
||||||
|
val instance = Random
|
||||||
|
discardSomeValues(instance)
|
||||||
|
assertSame(instance, serializeAndDeserialize(instance))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun discardSomeValues(instance: Random) {
|
||||||
|
instance.nextInt()
|
||||||
|
instance.nextDouble()
|
||||||
|
instance.nextLong()
|
||||||
|
instance.nextBytes(64)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun testRandomsHaveSameState(first: Random, second: Random) {
|
||||||
|
assertEquals(first.nextInt(), second.nextInt())
|
||||||
|
assertEquals(first.nextDouble(), second.nextDouble())
|
||||||
|
assertEquals(first.nextLong(), second.nextLong())
|
||||||
|
assertTrue(first.nextBytes(64).contentEquals(second.nextBytes(64)))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun deserializeDefault() = assertSame(
|
||||||
|
expected = Random,
|
||||||
|
actual = deserializeFromHex("ac ed 00 05 73 72 00 22 6b 6f 74 6c 69 6e 2e 72 61 6e 64 6f 6d 2e 52 61 6e 64 6f 6d 24 44 65 66 61 75 6c 74 24 44 75 6d 6d 79 00 00 00 00 00 00 00 00 02 00 00 78 70"),
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun deserializeXorWow() {
|
||||||
|
val instance = Random(0)
|
||||||
|
|
||||||
|
val deserialized =
|
||||||
|
deserializeFromHex<Random>("ac ed 00 05 73 72 00 1a 6b 6f 74 6c 69 6e 2e 72 61 6e 64 6f 6d 2e 58 6f 72 57 6f 77 52 61 6e 64 6f 6d 00 00 00 00 00 00 00 00 02 00 06 49 00 06 61 64 64 65 6e 64 49 00 01 76 49 00 01 77 49 00 01 78 49 00 01 79 49 00 01 7a 78 70 01 61 f1 40 23 9d 3d b3 c9 07 82 1d 6a 67 48 b0 e3 f9 bd 0c b6 5b de 32")
|
||||||
|
|
||||||
|
testRandomsHaveSameState(instance, deserialized)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun xorwowIsSerializable() {
|
||||||
|
val instance = Random(0)
|
||||||
|
discardSomeValues(instance)
|
||||||
|
val deserialized = serializeAndDeserialize(instance)
|
||||||
|
testRandomsHaveSameState(instance, deserialized)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wrapperOfKotlinRandomIsSerializable() {
|
||||||
|
val java = Random(0).asJavaRandom()
|
||||||
|
java.nextInt()
|
||||||
|
java.nextDouble()
|
||||||
|
java.nextLong()
|
||||||
|
java.nextBytes(ByteArray(64) { 0 })
|
||||||
|
val deserialized = serializeAndDeserialize(java)
|
||||||
|
testRandomsHaveSameState(java.asKotlinRandom(), deserialized.asKotlinRandom())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wrapperOfJavaRandomIsSerializable() {
|
||||||
|
val kotlin = java.util.Random(0).asKotlinRandom()
|
||||||
|
discardSomeValues(kotlin)
|
||||||
|
val deserialized = serializeAndDeserialize(kotlin)
|
||||||
|
testRandomsHaveSameState(kotlin, deserialized)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -267,10 +267,17 @@ public abstract class Random {
|
|||||||
*
|
*
|
||||||
* @sample samples.random.Randoms.defaultRandom
|
* @sample samples.random.Randoms.defaultRandom
|
||||||
*/
|
*/
|
||||||
companion object Default : Random() {
|
companion object Default : Random(), Serializable {
|
||||||
|
|
||||||
private val defaultRandom: Random = defaultPlatformRandom()
|
private val defaultRandom: Random = defaultPlatformRandom()
|
||||||
|
|
||||||
|
private object Dummy : Serializable {
|
||||||
|
private const val serialVersionUID = 0L
|
||||||
|
|
||||||
|
private fun readResolve(): Any = Random
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeReplace(): Any = Dummy
|
||||||
|
|
||||||
override fun nextBits(bitCount: Int): Int = defaultRandom.nextBits(bitCount)
|
override fun nextBits(bitCount: Int): Int = defaultRandom.nextBits(bitCount)
|
||||||
override fun nextInt(): Int = defaultRandom.nextInt()
|
override fun nextInt(): Int = defaultRandom.nextInt()
|
||||||
override fun nextInt(until: Int): Int = defaultRandom.nextInt(until)
|
override fun nextInt(until: Int): Int = defaultRandom.nextInt(until)
|
||||||
@@ -290,7 +297,8 @@ public abstract class Random {
|
|||||||
|
|
||||||
override fun nextBytes(array: ByteArray): ByteArray = defaultRandom.nextBytes(array)
|
override fun nextBytes(array: ByteArray): ByteArray = defaultRandom.nextBytes(array)
|
||||||
override fun nextBytes(size: Int): ByteArray = defaultRandom.nextBytes(size)
|
override fun nextBytes(size: Int): ByteArray = defaultRandom.nextBytes(size)
|
||||||
override fun nextBytes(array: ByteArray, fromIndex: Int, toIndex: Int): ByteArray = defaultRandom.nextBytes(array, fromIndex, toIndex)
|
override fun nextBytes(array: ByteArray, fromIndex: Int, toIndex: Int): ByteArray =
|
||||||
|
defaultRandom.nextBytes(array, fromIndex, toIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,7 +333,6 @@ public fun Random(seed: Int): Random = XorWowRandom(seed, seed.shr(31))
|
|||||||
public fun Random(seed: Long): Random = XorWowRandom(seed.toInt(), seed.shr(32).toInt())
|
public fun Random(seed: Long): Random = XorWowRandom(seed.toInt(), seed.shr(32).toInt())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the next random `Int` from the random number generator in the specified [range].
|
* Gets the next random `Int` from the random number generator in the specified [range].
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -15,15 +15,14 @@ package kotlin.random
|
|||||||
* Available at https://www.jstatsoft.org/v08/i14/paper
|
* Available at https://www.jstatsoft.org/v08/i14/paper
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
internal class XorWowRandom
|
internal class XorWowRandom internal constructor(
|
||||||
internal constructor(
|
|
||||||
private var x: Int,
|
private var x: Int,
|
||||||
private var y: Int,
|
private var y: Int,
|
||||||
private var z: Int,
|
private var z: Int,
|
||||||
private var w: Int,
|
private var w: Int,
|
||||||
private var v: Int,
|
private var v: Int,
|
||||||
private var addend: Int
|
private var addend: Int
|
||||||
) : Random() {
|
) : Random(), Serializable {
|
||||||
|
|
||||||
internal constructor(seed1: Int, seed2: Int) :
|
internal constructor(seed1: Int, seed2: Int) :
|
||||||
this(seed1, seed2, 0, 0, seed1.inv(), (seed1 shl 10) xor (seed2 ushr 4))
|
this(seed1, seed2, 0, 0, seed1.inv(), (seed1 shl 10) xor (seed2 ushr 4))
|
||||||
@@ -53,4 +52,8 @@ internal constructor(
|
|||||||
|
|
||||||
override fun nextBits(bitCount: Int): Int =
|
override fun nextBits(bitCount: Int): Int =
|
||||||
nextInt().takeUpperBits(bitCount)
|
nextInt().takeUpperBits(bitCount)
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
private const val serialVersionUID: Long = 0L
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -4232,7 +4232,7 @@ public abstract class kotlin/random/Random {
|
|||||||
public fun nextLong (JJ)J
|
public fun nextLong (JJ)J
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class kotlin/random/Random$Default : kotlin/random/Random {
|
public final class kotlin/random/Random$Default : kotlin/random/Random, java/io/Serializable {
|
||||||
public fun nextBits (I)I
|
public fun nextBits (I)I
|
||||||
public fun nextBoolean ()Z
|
public fun nextBoolean ()Z
|
||||||
public fun nextBytes (I)[B
|
public fun nextBytes (I)[B
|
||||||
|
|||||||
Reference in New Issue
Block a user