diff --git a/build.sc b/build.sc index a1666b2f..f2fcd69b 100644 --- a/build.sc +++ b/build.sc @@ -9,6 +9,11 @@ import com.github.lolgab.mill.mima._ import $ivy.`de.tototec::de.tobiasroeser.mill.jacoco_mill0.10:0.0.2` import de.tobiasroeser.mill.jacoco.JacocoTestModule +import de.tobiasroeser.mill.jacoco.JacocoReportModule + +object Jacoco extends Module with JacocoReportModule { + override lazy val jacocoVersion = T.input("0.8.8") +} object v { val munit = "1.0.0-M6" @@ -46,6 +51,7 @@ trait BaseModule extends ScalaModule with ScalafmtModule { ) trait BaseTest extends Tests with TestModule.Munit with JacocoTestModule with ScalafmtModule { + override val jacocoReportModule = Jacoco def ivyDeps = Agg( ivy"org.scalameta::munit:$munitVersion", ivy"org.scalameta::munit-scalacheck:$munitVersion" diff --git a/core/src/fr/hammons/slinc/Mem.scala b/core/src/fr/hammons/slinc/Mem.scala index 8b35dc73..d418a1c9 100644 --- a/core/src/fr/hammons/slinc/Mem.scala +++ b/core/src/fr/hammons/slinc/Mem.scala @@ -19,7 +19,7 @@ trait Mem: def readInt(offset: Bytes): Int def readFloat(offset: Bytes): Float def readByte(offset: Bytes): Byte - def readMem(offset: Bytes): Mem + def readAddress(offset: Bytes): Mem def readShort(offset: Bytes): Short def readLong(offset: Bytes): Long def readDouble(offset: Bytes): Double diff --git a/core/src/fr/hammons/slinc/Ptr.scala b/core/src/fr/hammons/slinc/Ptr.scala index 2e6e7c24..2e61ce49 100644 --- a/core/src/fr/hammons/slinc/Ptr.scala +++ b/core/src/fr/hammons/slinc/Ptr.scala @@ -11,7 +11,7 @@ class Ptr[A](private[slinc] val mem: Mem, private[slinc] val offset: Bytes): def asArray(size: Int)(using ClassTag[A] )(using l: LayoutOf[A], r: ReceiveBulk[A]) = - r.from(mem, offset, size) + r.from(mem.resize(Bytes(l.layout.size.toLong * size)), offset, size) def `unary_!_=`(value: A)(using send: Send[A]) = send.to(mem, offset, value) def apply(bytes: Bytes) = Ptr[A](mem, offset + bytes) @@ -19,14 +19,16 @@ class Ptr[A](private[slinc] val mem: Mem, private[slinc] val offset: Bytes): Ptr[A](mem, offset + (l.layout.size * index)) def castTo[A]: Ptr[A] = this.asInstanceOf[Ptr[A]] + private[slinc] def resize(toBytes: Bytes) = Ptr[A](mem.resize(toBytes), offset) object Ptr: extension (p: Ptr[Byte]) def copyIntoString(maxSize: Int)(using LayoutOf[Byte]) = var i = 0 - while !p(i) != 0 do i += 1 + val resizedPtr = p.resize(Bytes(maxSize)) + while (i < maxSize && !resizedPtr(i) != 0) do i += 1 - String(p.asArray(i).unsafeArray, "ASCII") + String(resizedPtr.asArray(i).unsafeArray, "ASCII") def blank[A](using layout: LayoutOf[A], alloc: Allocator): Ptr[A] = this.blankArray[A](1) diff --git a/core/src/fr/hammons/slinc/Receive.scala b/core/src/fr/hammons/slinc/Receive.scala index a62c1073..4d4a945b 100644 --- a/core/src/fr/hammons/slinc/Receive.scala +++ b/core/src/fr/hammons/slinc/Receive.scala @@ -47,6 +47,10 @@ object Receive: given Receive[Short] with def from(mem: Mem, offset: Bytes): Short = mem.readShort(offset) + given [A]: Receive[Ptr[A]] with + def from(mem: Mem, offset: Bytes): Ptr[A] = + Ptr[A](mem.readAddress(offset), Bytes(0)) + def staged[A <: Product]( layout: StructLayout ): JitCompiler => Receive[A] = @@ -97,7 +101,7 @@ object Receive: case _: ShortLayout => '{ $mem.readShort($structOffset) } case _: PointerLayout => - '{ $mem.readMem($structOffset) } + '{ $mem.readAddress($structOffset) } case u: UnionLayout => ??? case structLayout @ StructLayout(_, _, children) => diff --git a/core/src/fr/hammons/slinc/types/TypesI.scala b/core/src/fr/hammons/slinc/types/TypesI.scala index 095a2a37..03c2df66 100644 --- a/core/src/fr/hammons/slinc/types/TypesI.scala +++ b/core/src/fr/hammons/slinc/types/TypesI.scala @@ -25,6 +25,8 @@ class TypesI protected[slinc] ( type CShort = Int16 type CInt = Int32 type CLongLong = Int64 + type CFloat = Float + type CDouble = Double /** Type representing C's long type * @note diff --git a/core/test/src/fr/hammons/slinc/BindingsSpec.scala b/core/test/src/fr/hammons/slinc/StdlibSpec.scala similarity index 69% rename from core/test/src/fr/hammons/slinc/BindingsSpec.scala rename to core/test/src/fr/hammons/slinc/StdlibSpec.scala index 72dec011..3a7429c8 100644 --- a/core/test/src/fr/hammons/slinc/BindingsSpec.scala +++ b/core/test/src/fr/hammons/slinc/StdlibSpec.scala @@ -1,6 +1,6 @@ package fr.hammons.slinc -import fr.hammons.slinc.BindingsSpec.div_t +import fr.hammons.slinc.StdlibSpec.{div_t, ldiv_t, lldiv_t} import scala.util.Random import munit.ScalaCheckSuite import org.scalacheck.Prop.* @@ -8,13 +8,15 @@ import org.scalacheck.Gen import org.scalacheck.Arbitrary import fr.hammons.slinc.types.OS -trait BindingsSpec(val slinc: Slinc) extends ScalaCheckSuite: +trait StdlibSpec(val slinc: Slinc) extends ScalaCheckSuite: import slinc.{given, *} object Cstd derives Library: def abs(a: Int): Int = Library.binding def labs(l: CLong): CLong = Library.binding def div(a: Int, b: Int): div_t = Library.binding + //def ldiv(a: Long, b: Long): ldiv_t = Library.binding + //def lldiv(a: Long, b: Long): lldiv_t = Library.binding def rand(): Int = Library.binding def qsort[A]( array: Ptr[A], @@ -24,6 +26,9 @@ trait BindingsSpec(val slinc: Slinc) extends ScalaCheckSuite: ): Unit = Library.binding def sprintf(ret: Ptr[Byte], string: Ptr[Byte], args: Variadic*): Unit = Library.binding + def atof(str: Ptr[Byte]): CDouble = Library.binding + def strtod(str: Ptr[Byte], endptr: Ptr[Ptr[Byte]]): CDouble = + Library.binding given Struct[div_t] = Struct.derived @@ -73,6 +78,15 @@ trait BindingsSpec(val slinc: Slinc) extends ScalaCheckSuite: assertEquals(Cstd.div(5, 2), div_t(2, 1)) } + /* + test("ldiv") { + assertEquals(Cstd.ldiv(5L, 2L), ldiv_t(2L, 1L)) + } + + test("lldiv") { + assertEquals(Cstd.lldiv(5L, 2L), lldiv_t(2L, 1L)) + } + */ test("rand") { assertNotEquals(Cstd.rand(), Cstd.rand()) } @@ -167,5 +181,53 @@ trait BindingsSpec(val slinc: Slinc) extends ScalaCheckSuite: ) } -object BindingsSpec: + property("atof convert strings to floats") { + forAll { (d: Double) => + Scope.confined { + val pStr = Ptr.copy(f"$d%f") + assertEqualsDouble(Cstd.atof(pStr), d, 0.1) + } + } + } + + property("strtod convert doubles from string") { + forAll {(d: Double) => + Scope.confined { + val input = f"$d%f $d%f" + val maxSize = input.length() + val pStr0 = Ptr.copy(input) + + val ans1 = Ptr.blank[Ptr[Byte]] + val a1 = Cstd.strtod(pStr0, ans1) + assertEqualsDouble(a1, d, 0.1) + val pStr1 = !ans1 + val r1 = pStr1.copyIntoString(maxSize) + assertEquals(r1, f" $d%f") + + val ans2 = Ptr.blank[Ptr[Byte]] + val a2 = Cstd.strtod(pStr1, ans2) + assertEqualsDouble(a2, d, 0.1) + assertEquals(!(!ans2), 0.toByte) + } + } + } + + test("strtod convert bad string") { + Scope.confined { + val input = "notPossible" + val maxSize = input.length() + val pStr0 = Ptr.copy(input) + + val ans1 = Ptr.blank[Ptr[Byte]] + val a = Cstd.strtod(pStr0, ans1) + assertEqualsDouble(a, 0.0d, 0.1) + val pStr1 = !ans1 + val r1 = pStr1.copyIntoString(maxSize) + assertEquals(r1, input) + } + } + +object StdlibSpec: case class div_t(quot: Int, rem: Int) + case class ldiv_t(quot: Long, rem: Long) + case class lldiv_t(quot: Long, rem: Long) diff --git a/j17/src/fr/hammons/slinc/Mem17.scala b/j17/src/fr/hammons/slinc/Mem17.scala index 75dd1c3e..65b7f613 100644 --- a/j17/src/fr/hammons/slinc/Mem17.scala +++ b/j17/src/fr/hammons/slinc/Mem17.scala @@ -2,7 +2,8 @@ package fr.hammons.slinc import jdk.incubator.foreign.MemorySegment import jdk.incubator.foreign.MemoryAccess -import jdk.incubator.foreign.CLinker.C_POINTER +import jdk.incubator.foreign.ResourceScope +import jdk.incubator.foreign.CLinker.{C_CHAR, C_INT} class Mem17(private[slinc] val mem: MemorySegment) extends Mem: override def readDouble(offset: Bytes): Double = @@ -20,7 +21,18 @@ class Mem17(private[slinc] val mem: MemorySegment) extends Mem: mem, offset.toLong ) - override def readMem(offset: Bytes): Mem = ??? + + override def readAddress(offset: Bytes): Mem = + Mem17( + MemoryAccess + .getAddressAtOffset( + mem, + offset.toLong + ).nn.asSegment( + C_CHAR.nn.byteSize(), + ResourceScope.globalScope() + ).nn + ) override def writeInt(v: Int, offset: Bytes): Unit = MemoryAccess.setIntAtOffset(mem, offset.toLong, v) @@ -55,9 +67,16 @@ class Mem17(private[slinc] val mem: MemorySegment) extends Mem: def asBase: Object = mem def resize(bytes: Bytes): Mem = - Mem17(mem.address().nn.asSegment(bytes.toLong, mem.scope().nn).nn) + Mem17(resizeSegment(bytes)) + + def resizeSegment(to: Bytes): MemorySegment = + if to.toLong == 0 then + mem + else + mem.address().nn.asSegment(to.toLong, mem.scope().nn).nn def readIntArray(offset: Bytes, size: Int): Array[Int] = val arr = Array.ofDim[Int](size) - MemorySegment.ofArray(arr).nn.copyFrom(mem) + val resizedMem = resizeSegment(Bytes(size * C_INT.nn.byteSize())) + MemorySegment.ofArray(arr).nn.copyFrom(resizedMem) arr diff --git a/j17/test/src/fr/hammons/slinc/BindingsSpec.scala b/j17/test/src/fr/hammons/slinc/StdlibSpec.scala similarity index 60% rename from j17/test/src/fr/hammons/slinc/BindingsSpec.scala rename to j17/test/src/fr/hammons/slinc/StdlibSpec.scala index b9667841..fef2044d 100644 --- a/j17/test/src/fr/hammons/slinc/BindingsSpec.scala +++ b/j17/test/src/fr/hammons/slinc/StdlibSpec.scala @@ -3,4 +3,4 @@ package fr.hammons.slinc import Slinc17.default.{given, *} import scala.util.Random -class Bindings17 extends BindingsSpec(Slinc17.default) +class StdlibSpec17 extends StdlibSpec(Slinc17.default) diff --git a/j19/src/fr/hammons/slinc/Mem19.scala b/j19/src/fr/hammons/slinc/Mem19.scala index d387db5c..bd39e1bc 100644 --- a/j19/src/fr/hammons/slinc/Mem19.scala +++ b/j19/src/fr/hammons/slinc/Mem19.scala @@ -1,15 +1,18 @@ package fr.hammons.slinc import java.lang.foreign.MemorySegment +import java.lang.foreign.MemorySession import java.lang.foreign.ValueLayout, ValueLayout.* object Mem19: val javaShort = JAVA_SHORT.nn.withBitAlignment(8) val javaInt = JAVA_INT.nn.withBitAlignment(8) + val javaChar = JAVA_CHAR.nn.withBitAlignment(8) val javaLong = JAVA_LONG.nn.withBitAlignment(8) val javaFloat = JAVA_FLOAT.nn.withBitAlignment(8) val javaDouble = JAVA_DOUBLE.nn.withBitAlignment(8) val javaByte = JAVA_BYTE.nn.withBitAlignment(8) + val javaAddress = ADDRESS.nn.withBitAlignment(8) class Mem19(private[slinc] val mem: MemorySegment) extends Mem: import Mem19.* @@ -41,12 +44,21 @@ class Mem19(private[slinc] val mem: MemorySegment) extends Mem: override def readFloat(offset: Bytes): Float = mem.get(javaFloat, offset.toLong) - override def readMem(offset: Bytes): Mem = ??? + override def readAddress(offset: Bytes): Mem = Mem19( + MemorySegment.ofAddress( + mem.get(javaAddress, offset.toLong).nn, + javaChar.nn.byteSize(), + MemorySession.global() + ).nn + ) override def resize(bytes: Bytes): Mem = Mem19( - MemorySegment.ofAddress(mem.address().nn, bytes.toLong, mem.session()).nn + resizeSegment(bytes) ) + def resizeSegment(to: Bytes): MemorySegment = + MemorySegment.ofAddress(mem.address().nn, to.toLong, mem.session()).nn + override def readByte(offset: Bytes): Byte = mem.get(javaByte, offset.toLong) override def writeFloat(v: Float, offset: Bytes): Unit = @@ -66,5 +78,6 @@ class Mem19(private[slinc] val mem: MemorySegment) extends Mem: override def readIntArray(offset: Bytes, size: Int): Array[Int] = val arr = Array.ofDim[Int](size) - MemorySegment.ofArray(arr).nn.copyFrom(mem) + val resizedMem = resizeSegment(Bytes(size * javaInt.nn.byteSize())) + MemorySegment.ofArray(arr).nn.copyFrom(resizedMem) arr diff --git a/j19/test/src/fr/hammons/slinc/Bindings19.scala b/j19/test/src/fr/hammons/slinc/StdlibSpec.scala similarity index 76% rename from j19/test/src/fr/hammons/slinc/Bindings19.scala rename to j19/test/src/fr/hammons/slinc/StdlibSpec.scala index c6832a58..758596d5 100644 --- a/j19/test/src/fr/hammons/slinc/Bindings19.scala +++ b/j19/test/src/fr/hammons/slinc/StdlibSpec.scala @@ -5,4 +5,4 @@ import java.lang.foreign.SymbolLookup import java.lang.foreign.FunctionDescriptor import java.lang.foreign.ValueLayout.* -class Bindings19 extends BindingsSpec(Slinc19.default) +class StdlibSpec19 extends StdlibSpec(Slinc19.default) diff --git a/runtime/test/src/fr/hammons/slinc/Bindings.scala b/runtime/test/src/fr/hammons/slinc/Bindings.scala index a29eb95b..086362c9 100644 --- a/runtime/test/src/fr/hammons/slinc/Bindings.scala +++ b/runtime/test/src/fr/hammons/slinc/Bindings.scala @@ -9,4 +9,4 @@ object Mytest derives Library: val x = println(Mytest.abs(3)) -class Bindings extends BindingsSpec(slinc) +class Bindings extends StdlibSpec(slinc)