mirror of
https://github.com/corda/corda.git
synced 2025-03-10 22:44:20 +00:00
Backport of ENT-1303 applied to 3.0-RC3 (#2332)
This commit is contained in:
parent
5924427659
commit
c5149bab9f
@ -13,8 +13,22 @@ import javax.xml.bind.DatatypeConverter
|
|||||||
*/
|
*/
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
sealed class ByteSequence : Comparable<ByteSequence> {
|
sealed class ByteSequence : Comparable<ByteSequence> {
|
||||||
|
constructor() {
|
||||||
|
this._bytes = COPY_BYTES
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The underlying bytes.
|
* This constructor allows to bypass calls to [bytes] for functions in this class if the implementation
|
||||||
|
* of [bytes] makes a copy of the underlying [ByteArray] (as [OpaqueBytes] does for safety). This improves
|
||||||
|
* performance. It is recommended to use this constructor rather than the default constructor.
|
||||||
|
*/
|
||||||
|
constructor(uncopiedBytes: ByteArray) {
|
||||||
|
this._bytes = uncopiedBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The underlying bytes. Some implementations may choose to make a copy of the underlying [ByteArray] for
|
||||||
|
* security reasons. For example, [OpaqueBytes].
|
||||||
*/
|
*/
|
||||||
abstract val bytes: ByteArray
|
abstract val bytes: ByteArray
|
||||||
/**
|
/**
|
||||||
@ -26,8 +40,11 @@ sealed class ByteSequence : Comparable<ByteSequence> {
|
|||||||
*/
|
*/
|
||||||
abstract val offset: Int
|
abstract val offset: Int
|
||||||
|
|
||||||
|
private val _bytes: ByteArray
|
||||||
|
get() = if (field === COPY_BYTES) bytes else field
|
||||||
|
|
||||||
/** Returns a [ByteArrayInputStream] of the bytes */
|
/** Returns a [ByteArrayInputStream] of the bytes */
|
||||||
fun open() = ByteArrayInputStream(bytes, offset, size)
|
fun open() = ByteArrayInputStream(_bytes, offset, size)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a sub-sequence backed by the same array.
|
* Create a sub-sequence backed by the same array.
|
||||||
@ -38,19 +55,22 @@ sealed class ByteSequence : Comparable<ByteSequence> {
|
|||||||
fun subSequence(offset: Int, size: Int): ByteSequence {
|
fun subSequence(offset: Int, size: Int): ByteSequence {
|
||||||
require(offset >= 0)
|
require(offset >= 0)
|
||||||
require(offset + size <= this.size)
|
require(offset + size <= this.size)
|
||||||
|
// Intentionally use bytes rather than _bytes, to mirror the copy-or-not behaviour of that property.
|
||||||
return if (offset == 0 && size == this.size) this else of(bytes, this.offset + offset, size)
|
return if (offset == 0 && size == this.size) this else of(bytes, this.offset + offset, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
* Construct a [ByteSequence] given a [ByteArray] and optional offset and size, that represents that potentially
|
* Construct a [ByteSequence] given a [ByteArray] and optional offset and size, that represents that potentially
|
||||||
* sub-sequence of bytes. The returned implementation is optimised when the whole [ByteArray] is the sequence.
|
* sub-sequence of bytes.
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun of(bytes: ByteArray, offset: Int = 0, size: Int = bytes.size): ByteSequence {
|
fun of(bytes: ByteArray, offset: Int = 0, size: Int = bytes.size): ByteSequence {
|
||||||
return if (offset == 0 && size == bytes.size && size != 0) OpaqueBytes(bytes) else OpaqueBytesSubSequence(bytes, offset, size)
|
return OpaqueBytesSubSequence(bytes, offset, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val COPY_BYTES: ByteArray = ByteArray(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,7 +85,7 @@ sealed class ByteSequence : Comparable<ByteSequence> {
|
|||||||
* Copy this sequence, complete with new backing array. This can be helpful to break references to potentially
|
* Copy this sequence, complete with new backing array. This can be helpful to break references to potentially
|
||||||
* large backing arrays from small sub-sequences.
|
* large backing arrays from small sub-sequences.
|
||||||
*/
|
*/
|
||||||
fun copy(): ByteSequence = of(bytes.copyOfRange(offset, offset + size))
|
fun copy(): ByteSequence = of(_bytes.copyOfRange(offset, offset + size))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare byte arrays byte by byte. Arrays that are shorter are deemed less than longer arrays if all the bytes
|
* Compare byte arrays byte by byte. Arrays that are shorter are deemed less than longer arrays if all the bytes
|
||||||
@ -73,10 +93,12 @@ sealed class ByteSequence : Comparable<ByteSequence> {
|
|||||||
*/
|
*/
|
||||||
override fun compareTo(other: ByteSequence): Int {
|
override fun compareTo(other: ByteSequence): Int {
|
||||||
val min = minOf(this.size, other.size)
|
val min = minOf(this.size, other.size)
|
||||||
|
val thisBytes = this._bytes
|
||||||
|
val otherBytes = other._bytes
|
||||||
// Compare min bytes
|
// Compare min bytes
|
||||||
for (index in 0 until min) {
|
for (index in 0 until min) {
|
||||||
val unsignedThis = java.lang.Byte.toUnsignedInt(this.bytes[this.offset + index])
|
val unsignedThis = java.lang.Byte.toUnsignedInt(thisBytes[this.offset + index])
|
||||||
val unsignedOther = java.lang.Byte.toUnsignedInt(other.bytes[other.offset + index])
|
val unsignedOther = java.lang.Byte.toUnsignedInt(otherBytes[other.offset + index])
|
||||||
if (unsignedThis != unsignedOther) {
|
if (unsignedThis != unsignedOther) {
|
||||||
return Integer.signum(unsignedThis - unsignedOther)
|
return Integer.signum(unsignedThis - unsignedOther)
|
||||||
}
|
}
|
||||||
@ -89,7 +111,7 @@ sealed class ByteSequence : Comparable<ByteSequence> {
|
|||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other !is ByteSequence) return false
|
if (other !is ByteSequence) return false
|
||||||
if (this.size != other.size) return false
|
if (this.size != other.size) return false
|
||||||
return subArraysEqual(this.bytes, this.offset, this.size, other.bytes, other.offset)
|
return subArraysEqual(this._bytes, this.offset, this.size, other._bytes, other.offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun subArraysEqual(a: ByteArray, aOffset: Int, length: Int, b: ByteArray, bOffset: Int): Boolean {
|
private fun subArraysEqual(a: ByteArray, aOffset: Int, length: Int, b: ByteArray, bOffset: Int): Boolean {
|
||||||
@ -103,14 +125,15 @@ sealed class ByteSequence : Comparable<ByteSequence> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
|
val thisBytes = _bytes
|
||||||
var result = 1
|
var result = 1
|
||||||
for (index in offset until (offset + size)) {
|
for (index in offset until (offset + size)) {
|
||||||
result = 31 * result + bytes[index]
|
result = 31 * result + thisBytes[index]
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String = "[${bytes.copyOfRange(offset, offset + size).toHexString()}]"
|
override fun toString(): String = "[${_bytes.copyOfRange(offset, offset + size).toHexString()}]"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,7 +141,7 @@ sealed class ByteSequence : Comparable<ByteSequence> {
|
|||||||
* In an ideal JVM this would be a value type and be completely overhead free. Project Valhalla is adding such
|
* In an ideal JVM this would be a value type and be completely overhead free. Project Valhalla is adding such
|
||||||
* functionality to Java, but it won't arrive for a few years yet!
|
* functionality to Java, but it won't arrive for a few years yet!
|
||||||
*/
|
*/
|
||||||
open class OpaqueBytes(bytes: ByteArray) : ByteSequence() {
|
open class OpaqueBytes(bytes: ByteArray) : ByteSequence(bytes) {
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
* Create [OpaqueBytes] from a sequence of [Byte] values.
|
* Create [OpaqueBytes] from a sequence of [Byte] values.
|
||||||
@ -147,7 +170,7 @@ open class OpaqueBytes(bytes: ByteArray) : ByteSequence() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy [size] bytes from this [ByteArray] starting from [offset] into a new [ByteArray].
|
* Wrap [size] bytes from this [ByteArray] starting from [offset] into a new [ByteArray].
|
||||||
*/
|
*/
|
||||||
fun ByteArray.sequence(offset: Int = 0, size: Int = this.size) = ByteSequence.of(this, offset, size)
|
fun ByteArray.sequence(offset: Int = 0, size: Int = this.size) = ByteSequence.of(this, offset, size)
|
||||||
|
|
||||||
@ -165,7 +188,7 @@ fun String.parseAsHex(): ByteArray = DatatypeConverter.parseHexBinary(this)
|
|||||||
/**
|
/**
|
||||||
* Class is public for serialization purposes
|
* Class is public for serialization purposes
|
||||||
*/
|
*/
|
||||||
class OpaqueBytesSubSequence(override val bytes: ByteArray, override val offset: Int, override val size: Int) : ByteSequence() {
|
class OpaqueBytesSubSequence(override val bytes: ByteArray, override val offset: Int, override val size: Int) : ByteSequence(bytes) {
|
||||||
init {
|
init {
|
||||||
require(offset >= 0 && offset < bytes.size)
|
require(offset >= 0 && offset < bytes.size)
|
||||||
require(size >= 0 && size <= bytes.size)
|
require(size >= 0 && size <= bytes.size)
|
||||||
|
@ -14,7 +14,7 @@ class OpaqueBytesSubSequenceSerializer(factory: SerializerFactory) :
|
|||||||
CustomSerializer.Proxy<OpaqueBytesSubSequence, OpaqueBytes>(OpaqueBytesSubSequence::class.java, OpaqueBytes::class.java, factory) {
|
CustomSerializer.Proxy<OpaqueBytesSubSequence, OpaqueBytes>(OpaqueBytesSubSequence::class.java, OpaqueBytes::class.java, factory) {
|
||||||
override val additionalSerializers: Iterable<CustomSerializer<out Any>> = emptyList()
|
override val additionalSerializers: Iterable<CustomSerializer<out Any>> = emptyList()
|
||||||
|
|
||||||
override fun toProxy(obj: OpaqueBytesSubSequence): OpaqueBytes = obj.copy() as OpaqueBytes
|
override fun toProxy(obj: OpaqueBytesSubSequence): OpaqueBytes = OpaqueBytes(obj.copy().bytes)
|
||||||
|
|
||||||
override fun fromProxy(proxy: OpaqueBytes): OpaqueBytesSubSequence = OpaqueBytesSubSequence(proxy.bytes, proxy.offset, proxy.size)
|
override fun fromProxy(proxy: OpaqueBytes): OpaqueBytesSubSequence = OpaqueBytesSubSequence(proxy.bytes, proxy.offset, proxy.size)
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user