diff --git a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt index 930b21095..77157d91c 100644 --- a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt +++ b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt @@ -57,6 +57,7 @@ public interface MemoryReader { /** * Reads [Float] at certain [offset]. */ + @Deprecated("readFloat and writeFloat functions work unexpectedly on JS platform, since because their results are widened when used. Consider using readDouble and writeDouble.") public fun readFloat(offset: Int): Float /** @@ -113,6 +114,7 @@ public interface MemoryWriter { /** * Writes [Float] at certain [offset]. */ + @Deprecated("readFloat and writeFloat functions work unexpectedly on JS platform, since because their results are widened when used. Consider using readDouble and writeDouble.") public fun writeFloat(offset: Int, value: Float) /** diff --git a/kmath-memory/src/commonTest/kotlin/kscience/kmath/memory/MemoryTest.kt b/kmath-memory/src/commonTest/kotlin/kscience/kmath/memory/MemoryTest.kt new file mode 100644 index 000000000..3c3a5e506 --- /dev/null +++ b/kmath-memory/src/commonTest/kotlin/kscience/kmath/memory/MemoryTest.kt @@ -0,0 +1,88 @@ +package kscience.kmath.memory + +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class MemoryTest { + @Test + fun allocateReturnsMemoryWithValidSize() { + val mem = Memory.allocate(64) + assertEquals(64, mem.size) + } + + @Test + fun rwByte() { + val mem = Memory.allocate(64) + mem.write { writeByte(0, 42.toByte()) } + assertEquals(42.toByte(), mem.read { readByte(0) }) + mem.write { writeByte(1, (-4).toByte()) } + assertEquals((-4).toByte(), mem.read { readByte(1) }) + } + + @Test + fun rwShort() { + val mem = Memory.allocate(64) + mem.write { writeShort(0, 44555.toShort()) } + assertEquals(44555.toShort(), mem.read { readShort(0) }) + mem.write { writeShort(2, (-33333).toShort()) } + assertEquals((-33333).toShort(), mem.read { readShort(2) }) + } + + @Test + fun rwInt() { + val mem = Memory.allocate(64) + mem.write { writeInt(0, 1234444444) } + assertEquals(1234444444, mem.read { readInt(0) }) + mem.write { writeInt(4, -5595959) } + assertEquals(-5595959, mem.read { readInt(4) }) + } + + @Test + fun rwLong() { + val mem = Memory.allocate(64) + mem.write { writeLong(0, 1234444444L) } + assertEquals(1234444444L, mem.read { readLong(0) }) + mem.write { writeLong(4, -5595959L) } + assertEquals(-5595959L, mem.read { readLong(4) }) + mem.write { writeLong(8, 1234444444444149L) } + assertEquals(1234444444444149L, mem.read { readLong(8) }) + mem.write { writeLong(16, -50000333595959L) } + assertEquals(-50000333595959L, mem.read { readLong(16) }) + } + + @Suppress("DEPRECATION") + @Test + fun rwFloat() { + val mem = Memory.allocate(64) + mem.write { writeFloat(0, 12.12345f) } + println(1) + assertEquals(12.12345027923584, mem.read { readFloat(0) }.toDouble()) + mem.write { writeFloat(4, -313.13f) } + println(2) + assertEquals(-313.1300048828125, mem.read { readFloat(4) }.toDouble()) + mem.write { writeFloat(8, Float.NaN) } + println(3) + assertEquals(Float.NaN, mem.read { readFloat(8) }) + mem.write { writeFloat(12, Float.POSITIVE_INFINITY) } + println(4) + assertEquals(Float.POSITIVE_INFINITY, mem.read { readFloat(12) }) + mem.write { writeFloat(12, Float.NEGATIVE_INFINITY) } + println(5) + assertEquals(Float.NEGATIVE_INFINITY, mem.read { readFloat(12) }) + } + + @Test + fun rwDouble() { + val mem = Memory.allocate(64) + mem.write { writeDouble(0, 12.12345) } + assertEquals(12.12345, mem.read { readDouble(0) }) + mem.write { writeDouble(8, -313.13) } + assertEquals(-313.13, mem.read { readDouble(8) }) + mem.write { writeDouble(16, Double.NaN) } + assertEquals(Double.NaN, mem.read { readDouble(16) }) + mem.write { writeDouble(24, Double.POSITIVE_INFINITY) } + assertEquals(Double.POSITIVE_INFINITY, mem.read { readDouble(24) }) + mem.write { writeDouble(32, Double.NEGATIVE_INFINITY) } + assertEquals(Double.NEGATIVE_INFINITY, mem.read { readDouble(32) }) + } +} diff --git a/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt b/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt index 9a622ea36..6c9d153b5 100644 --- a/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt +++ b/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt @@ -28,18 +28,18 @@ private class DataViewMemory(val view: DataView) : Memory { private val reader: MemoryReader = object : MemoryReader { override val memory: Memory get() = this@DataViewMemory - override fun readDouble(offset: Int): Double = view.getFloat64(offset, false) + override fun readDouble(offset: Int): Double = view.getFloat64(offset, true) - override fun readFloat(offset: Int): Float = view.getFloat32(offset, false) + override fun readFloat(offset: Int): Float = view.getFloat32(offset, true) override fun readByte(offset: Int): Byte = view.getInt8(offset) - override fun readShort(offset: Int): Short = view.getInt16(offset, false) + override fun readShort(offset: Int): Short = view.getInt16(offset, true) - override fun readInt(offset: Int): Int = view.getInt32(offset, false) + override fun readInt(offset: Int): Int = view.getInt32(offset, true) override fun readLong(offset: Int): Long = - view.getInt32(offset, false).toLong() shl 32 or view.getInt32(offset + 4, false).toLong() + view.getInt32(offset, true).toLong() shl 32 or view.getInt32(offset + 4, true).toLong() override fun release() { // does nothing on JS @@ -52,11 +52,11 @@ private class DataViewMemory(val view: DataView) : Memory { override val memory: Memory get() = this@DataViewMemory override fun writeDouble(offset: Int, value: Double) { - view.setFloat64(offset, value, false) + view.setFloat64(offset, value, true) } override fun writeFloat(offset: Int, value: Float) { - view.setFloat32(offset, value, false) + view.setFloat32(offset, value, true) } override fun writeByte(offset: Int, value: Byte) { @@ -64,16 +64,16 @@ private class DataViewMemory(val view: DataView) : Memory { } override fun writeShort(offset: Int, value: Short) { - view.setUint16(offset, value, false) + view.setUint16(offset, value, true) } override fun writeInt(offset: Int, value: Int) { - view.setInt32(offset, value, false) + view.setInt32(offset, value, true) } override fun writeLong(offset: Int, value: Long) { - view.setInt32(offset, (value shr 32).toInt(), littleEndian = false) - view.setInt32(offset + 4, (value and 0xffffffffL).toInt(), littleEndian = false) + view.setInt32(offset, (value shr 32).toInt(), littleEndian = true) + view.setInt32(offset + 4, (value and 0xffffffffL).toInt(), littleEndian = true) } override fun release() { @@ -82,7 +82,6 @@ private class DataViewMemory(val view: DataView) : Memory { } override fun writer(): MemoryWriter = writer - } /** @@ -98,6 +97,6 @@ public actual fun Memory.Companion.allocate(length: Int): Memory { * and could be mutated independently from the resulting [Memory]. */ public actual fun Memory.Companion.wrap(array: ByteArray): Memory { - @Suppress("CAST_NEVER_SUCCEEDS") val int8Array = array as Int8Array + val int8Array = array.unsafeCast() return DataViewMemory(DataView(int8Array.buffer, int8Array.byteOffset, int8Array.length)) } diff --git a/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt b/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt index 944e8455b..2d8bb600c 100644 --- a/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt +++ b/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.memory import java.io.IOException import java.nio.ByteBuffer +import java.nio.ByteOrder import java.nio.channels.FileChannel import java.nio.file.Files import java.nio.file.Path @@ -31,7 +32,7 @@ internal class ByteBufferMemory( } override fun copy(): Memory { - val copy = ByteBuffer.allocate(buffer.capacity()) + val copy = ByteBuffer.allocate(buffer.capacity()).order(ByteOrder.LITTLE_ENDIAN) buffer.rewind() copy.put(buffer) copy.flip() @@ -99,7 +100,7 @@ internal class ByteBufferMemory( * Allocates memory based on a [ByteBuffer]. */ public actual fun Memory.Companion.allocate(length: Int): Memory = - ByteBufferMemory(checkNotNull(ByteBuffer.allocate(length))) + ByteBufferMemory(checkNotNull(ByteBuffer.allocate(length).order(ByteOrder.LITTLE_ENDIAN))) /** * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied diff --git a/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt b/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt index d31c9e8f4..97f503622 100644 --- a/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt +++ b/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt @@ -42,7 +42,7 @@ internal class NativeMemory( override fun readLong(offset: Int) = array.getLongAt(position(offset)) override fun release() { - // does nothing on JVM + // does nothing on Native } } @@ -60,7 +60,7 @@ internal class NativeMemory( } override fun writeByte(offset: Int, value: Byte) { - array.set(position(offset), value) + array[position(offset)] = value } override fun writeShort(offset: Int, value: Short) { @@ -76,7 +76,7 @@ internal class NativeMemory( } override fun release() { - // does nothing on JVM + // does nothing on Native } } @@ -95,4 +95,4 @@ public actual fun Memory.Companion.wrap(array: ByteArray): Memory = NativeMemory public actual fun Memory.Companion.allocate(length: Int): Memory { val array = ByteArray(length) return NativeMemory(array) -} \ No newline at end of file +}