Skip to content

Commit

Permalink
feat: add Transform types (#216)
Browse files Browse the repository at this point in the history
* feat: add Transform types

* chore: add tests for transforms
  • Loading branch information
markehammons authored Aug 16, 2023
1 parent 8e2ad0c commit 7089e46
Show file tree
Hide file tree
Showing 33 changed files with 263 additions and 299 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ jobs:
- uses: VirtusLab/[email protected]
with:
jvm: temurin:1.${{ matrix.jvm }}
apps: mill
- run: mill j${{ matrix.jvm }}.benchmarks.test -f1 -wi 2 -i 2 -o j${{ matrix.jvm }}-${{ matrix.os }}.bench -rff j${{ matrix.jvm }}-${{ matrix.os }}.json -rf json .*${{ matrix.benchmark }}${{ matrix.jit }}.*
- run: ./mill j${{ matrix.jvm }}.benchmarks.test -f1 -wi 2 -i 2 -o j${{ matrix.jvm }}-${{ matrix.os }}.bench -rff j${{ matrix.jvm }}-${{ matrix.os }}.json -rf json .*${{ matrix.benchmark }}${{ matrix.jit }}.*
- run: scala-cli run scripts/PublishBenchmarkReport.sc -- "Java ${{ matrix.jvm}}" ${{ matrix.os }} out/j${{ matrix.jvm }}/benchmarks/test/jmhRun.dest/j${{ matrix.jvm }}-${{ matrix.os }}.json ${{ matrix.benchmark }} ${{ matrix.jit }} >> $GITHUB_STEP_SUMMARY
- uses: actions/upload-artifact@v3
with:
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ jobs:
- uses: coursier/[email protected]
with:
jvm: temurin:1.17
apps: mill
- run: mill mill.scalalib.scalafmt.ScalafmtModule/checkFormatAll __.sources
- run: ./mill mill.scalalib.scalafmt.ScalafmtModule/checkFormatAll __.sources

unit-tests:
strategy:
Expand Down
2 changes: 1 addition & 1 deletion build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ trait BaseModule extends ScoverageModule with ScalafmtModule {
def scalaVersion = "3.3.0"
def scoverageVersion = "2.0.7"

val munitVersion = "1.0.0-M7"
val munitVersion = "1.0.0-M8"
val jmhV = "1.33"

def ivyDeps = Agg(
Expand Down
2 changes: 1 addition & 1 deletion core/src/fr/hammons/slinc/Allocator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import java.lang.invoke.{MethodHandle, MethodType, MethodHandles}
import fr.hammons.slinc.modules.DescriptorModule

trait Allocator:
def allocate(descriptor: TypeDescriptor, num: Int): Mem
def allocate(descriptor: ForeignTypeDescriptor, num: Int): Mem
def addCloseAction(fn: () => Unit): Unit
def upcall[Fn](descriptor: FunctionDescriptor, target: Fn): Mem
protected def methodHandleFromFn[Fn](
Expand Down
9 changes: 5 additions & 4 deletions core/src/fr/hammons/slinc/CUnion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ class CUnion[T <: Tuple](private[slinc] val mem: Mem):
setHelper[T, A](a)

object CUnion:
private inline def applyHelper[T <: Tuple](td: TypeDescriptor | Null)(using
DescriptorModule
): TypeDescriptor = inline erasedValue[T] match
private inline def applyHelper[T <: Tuple](td: ForeignTypeDescriptor | Null)(
using DescriptorModule
): ForeignTypeDescriptor = inline erasedValue[T] match
case _: (a *: t) =>
val aDesc = summonInline[DescriptorOf[a]].descriptor
val aDesc =
summonInline[DescriptorOf[a]].descriptor.toForeignTypeDescriptor
val max =
if td != null then
if td.size > aDesc.size then td
Expand Down
2 changes: 2 additions & 0 deletions core/src/fr/hammons/slinc/DescriptorOf.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ object DescriptorOf:
given DescriptorOf[VarArgs] with
val descriptor: TypeDescriptor { type Inner = VarArgs } = VaListDescriptor

given [A](using t: Transform[A, ?]): DescriptorOf[A] = t

def getDescriptorFor[A](using Quotes, Type[A]) =
import quotes.reflect.*
val expr = Expr
Expand Down
20 changes: 14 additions & 6 deletions core/src/fr/hammons/slinc/FunctionDescriptor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ final case class FunctionDescriptor(
case FunctionDescriptor(head +: tail, variadicDescriptors, None) =>
VoidHelper
.methodTypeV(
head.toCarrierType,
tail.view.concat(variadicDescriptors).map(_.toCarrierType).toSeq*
head.toForeignTypeDescriptor.toCarrierType,
tail.view
.concat(variadicDescriptors)
.map(_.toForeignTypeDescriptor.toCarrierType)
.toSeq*
)
.nn

Expand All @@ -35,15 +38,20 @@ final case class FunctionDescriptor(
) =>
MethodType
.methodType(
outputDescriptor.toCarrierType,
head.toCarrierType,
tail.view.concat(variadicDescriptors).map(_.toCarrierType).toSeq*
outputDescriptor.toForeignTypeDescriptor.toCarrierType,
head.toForeignTypeDescriptor.toCarrierType,
tail.view
.concat(variadicDescriptors)
.map(_.toForeignTypeDescriptor.toCarrierType)
.toSeq*
)
.nn

case FunctionDescriptor(_, _, None) => VoidHelper.methodTypeV().nn
case FunctionDescriptor(_, _, Some(outputDescriptor)) =>
MethodType.methodType(outputDescriptor.toCarrierType).nn
MethodType
.methodType(outputDescriptor.toForeignTypeDescriptor.toCarrierType)
.nn

object FunctionDescriptor:
def fromDefDef(using q: Quotes)(symbol: q.reflect.Symbol) =
Expand Down
17 changes: 12 additions & 5 deletions core/src/fr/hammons/slinc/Ptr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,18 @@ class Ptr[A](private[slinc] val mem: Mem, private[slinc] val offset: Bytes):
r: ReadWriteModule
)(using ClassTag[A]): IArray[A] =
IArray.unsafeFromArray(
r.readArray(mem.resize(DescriptorOf[A].size * size), offset, size)
r.readArray(
mem.resize(DescriptorOf[A].toForeignTypeDescriptor.size * size),
offset,
size
)
)

def `unary_!_=`(value: A)(using rwM: ReadWriteModule, desc: DescriptorOf[A]) =
rwM.write(mem, offset, desc.descriptor, value)
def apply(bytes: Bytes): Ptr[A] = Ptr[A](mem, offset + bytes)
def apply(index: Int)(using DescriptorOf[A], DescriptorModule): Ptr[A] =
Ptr[A](mem, offset + (DescriptorOf[A].size * index))
Ptr[A](mem, offset + (DescriptorOf[A].toForeignTypeDescriptor.size * index))

def castTo[A]: Ptr[A] = this.asInstanceOf[Ptr[A]]
private[slinc] def resize(toBytes: Bytes) =
Expand All @@ -59,12 +63,15 @@ object Ptr:
def blankArray[A](
num: Int
)(using descriptor: DescriptorOf[A], alloc: Allocator): Ptr[A] =
Ptr[A](alloc.allocate(DescriptorOf[A], num), Bytes(0))
Ptr[A](
alloc.allocate(DescriptorOf[A].toForeignTypeDescriptor, num),
Bytes(0)
)

def copy[A](
a: Array[A]
)(using alloc: Allocator, descriptor: DescriptorOf[A], rwm: ReadWriteModule) =
val mem = alloc.allocate(DescriptorOf[A], a.size)
val mem = alloc.allocate(DescriptorOf[A].toForeignTypeDescriptor, a.size)
rwm.writeArray(mem, Bytes(0), a)
Ptr[A](mem, Bytes(0))

Expand All @@ -76,7 +83,7 @@ object Ptr:
val descriptor: TypeDescriptor { type Inner = A }
}
) =
val mem = alloc.allocate(DescriptorOf[A], 1)
val mem = alloc.allocate(DescriptorOf[A].toForeignTypeDescriptor, 1)
rwm.write(mem, Bytes(0), descriptor.descriptor, a)
Ptr[A](mem, Bytes(0))

Expand Down
2 changes: 1 addition & 1 deletion core/src/fr/hammons/slinc/Slinc.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ trait Slinc:
export types.os

def sizeOf[A](using l: DescriptorOf[A]) =
SizeT.maybe(DescriptorOf[A].size.toLong).get
SizeT.maybe(DescriptorOf[A].toForeignTypeDescriptor.size.toLong).get

def Null[A] = scopePlatformSpecific.nullPtr[A]

Expand Down
6 changes: 4 additions & 2 deletions core/src/fr/hammons/slinc/Struct.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ object Struct:
rwm: ReadWriteModule,
dm: DescriptorModule
): Writer[A] =
val offsets = dm.memberOffsets(memberDescriptors[A])
val offsets =
dm.memberOffsets(memberDescriptors[A].map(_.toForeignTypeDescriptor))
(mem, offset, value) =>
writeGenHelper(
offsets.map(_ + offset),
Expand Down Expand Up @@ -67,7 +68,8 @@ object Struct:
rwm: ReadWriteModule,
dm: DescriptorModule
): Reader[A] =
val offsets: IArray[Bytes] = dm.memberOffsets(memberDescriptors[A])
val offsets: IArray[Bytes] =
dm.memberOffsets(memberDescriptors[A].map(_.toForeignTypeDescriptor))
(mem, offset) => {
val elems: m.MirroredElemTypes =
readGenHelper[m.MirroredElemTypes](offsets.map(_ + offset), 0, mem)
Expand Down
13 changes: 13 additions & 0 deletions core/src/fr/hammons/slinc/Transform.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package fr.hammons.slinc

trait Transform[A, B](using val desc: DescriptorOf[B])(
_transformFrom: B => A,
_transformTo: A => B
) extends DescriptorOf[A]:
val descriptor
: TransformDescriptor { type Inner = A; val cRep: desc.descriptor.type } =
new TransformDescriptor:
val cRep: desc.descriptor.type = desc.descriptor
type Inner = A
val transformFrom = _transformFrom
val transformTo = _transformTo
67 changes: 50 additions & 17 deletions core/src/fr/hammons/slinc/TypeDescriptor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ sealed trait TypeDescriptor:
type Inner
given DescriptorOf[Inner] with
val descriptor = self
def size(using dm: DescriptorModule): Bytes = dm.sizeOf(this)
def alignment(using dm: DescriptorModule): Bytes = dm.alignmentOf(this)
def toCarrierType(using dm: DescriptorModule): Class[?] =
dm.toCarrierType(this)

val reader: (ReadWriteModule, DescriptorModule) ?=> Reader[Inner]
val writer: (ReadWriteModule, DescriptorModule) ?=> Writer[Inner]
Expand All @@ -44,7 +40,7 @@ sealed trait TypeDescriptor:
Inner
] =
val reader = this.reader
val size = this.size
val size = this.toForeignTypeDescriptor.size
(mem, offset, num) => {
var i = 0
val array = Array.ofDim[Inner](num)
Expand All @@ -57,12 +53,22 @@ sealed trait TypeDescriptor:
val arrayWriter
: (ReadWriteModule, DescriptorModule) ?=> Writer[Array[Inner]] =
val writer = this.writer
val size = this.size
val size = this.toForeignTypeDescriptor.size
(mem, offset, a) =>
var i = 0
while i < a.length do
writer(mem, size * i + offset, a(i))
i += 1

def toForeignTypeDescriptor: ForeignTypeDescriptor

sealed trait ForeignTypeDescriptor extends TypeDescriptor:
def toForeignTypeDescriptor: ForeignTypeDescriptor = this
def size(using dm: DescriptorModule): Bytes = dm.sizeOf(this)
def alignment(using dm: DescriptorModule): Bytes = dm.alignmentOf(this)
def toCarrierType(using dm: DescriptorModule): Class[?] =
dm.toCarrierType(this)

object TypeDescriptor:
def fromTypeRepr(using q: Quotes)(
typeRepr: q.reflect.TypeRepr
Expand All @@ -83,7 +89,7 @@ object TypeDescriptor:

inline val unusedImplicit = "msg=unused implicit parameter"

sealed trait BasicDescriptor extends TypeDescriptor:
sealed trait BasicDescriptor extends ForeignTypeDescriptor:
override val argumentTransition = identity

override val returnTransition = _.asInstanceOf[Inner]
Expand Down Expand Up @@ -118,7 +124,7 @@ case object DoubleDescriptor extends BasicDescriptor:
val reader = readWriteModule.doubleReader
val writer = readWriteModule.doubleWriter

case object PtrDescriptor extends TypeDescriptor:
case object PtrDescriptor extends ForeignTypeDescriptor:
type Inner = Ptr[?]
override val reader = (mem, offset) =>
Ptr(readWriteModule.memReader(mem, offset), Bytes(0))
Expand Down Expand Up @@ -152,7 +158,7 @@ trait StructDescriptor(
val members: List[StructMemberDescriptor],
val clazz: Class[?],
val transform: Tuple => Product
) extends TypeDescriptor
) extends ForeignTypeDescriptor

case class AliasDescriptor[A](val real: TypeDescriptor) extends TypeDescriptor:
type Inner = A
Expand All @@ -174,13 +180,11 @@ case class AliasDescriptor[A](val real: TypeDescriptor) extends TypeDescriptor:
summon[TransitionModule].methodArgument(real, _, summon[Allocator])

override val returnTransition = summon[TransitionModule].methodReturn(real, _)
override def size(using dm: DescriptorModule): Bytes = dm.sizeOf(real)
override def alignment(using dm: DescriptorModule): Bytes =
dm.alignmentOf(real)
override def toCarrierType(using dm: DescriptorModule): Class[?] =
dm.toCarrierType(real)

case object VaListDescriptor extends TypeDescriptor:
def toForeignTypeDescriptor: ForeignTypeDescriptor =
real.toForeignTypeDescriptor

case object VaListDescriptor extends ForeignTypeDescriptor:
type Inner = VarArgs

override val reader: (ReadWriteModule, DescriptorModule) ?=> Reader[Inner] =
Expand All @@ -200,7 +204,7 @@ case object VaListDescriptor extends TypeDescriptor:
summon[TransitionModule].addressReturn(o).asVarArgs

case class CUnionDescriptor(possibleTypes: Set[TypeDescriptor])
extends TypeDescriptor:
extends ForeignTypeDescriptor:
type Inner = CUnion[? <: NonEmptyTuple]

override val reader: (ReadWriteModule, DescriptorModule) ?=> Reader[Inner] =
Expand All @@ -223,7 +227,7 @@ case class SetSizeArrayDescriptor(
val contained: TypeDescriptor,
val number: Int
)(using ClassTag[contained.Inner])
extends TypeDescriptor:
extends ForeignTypeDescriptor:

override val reader: (ReadWriteModule, DescriptorModule) ?=> Reader[Inner] =
(mem, offset) =>
Expand Down Expand Up @@ -256,3 +260,32 @@ case class SetSizeArrayDescriptor(
summon[ReadWriteModule].read(mem, Bytes(0), this)

type Inner = SetSizeArray[contained.Inner, ?]

trait TransformDescriptor extends TypeDescriptor:
val cRep: TypeDescriptor
val transformTo: Inner => cRep.Inner
val transformFrom: cRep.Inner => Inner

protected inline def toInner[A <: Matchable](a: A) =
import scala.compiletime.error
inline a match
case b: cRep.Inner => b
case _ => error("cannot convert")

override val reader: (ReadWriteModule, DescriptorModule) ?=> Reader[Inner] =
(mem: Mem, bytes: Bytes) => transformFrom(cRep.reader(mem, bytes))

override val writer: (ReadWriteModule, DescriptorModule) ?=> Writer[Inner] =
(mem, bytes, value) => cRep.writer(mem, bytes, transformTo(value))

override val argumentTransition
: (TransitionModule, ReadWriteModule, Allocator) ?=> ArgumentTransition[
Inner
] = cRep.argumentTransition.compose(transformTo)

override val returnTransition
: (TransitionModule, ReadWriteModule) ?=> ReturnTransition[Inner] =
cRep.returnTransition.andThen(transformFrom)

def toForeignTypeDescriptor: ForeignTypeDescriptor =
cRep.toForeignTypeDescriptor
11 changes: 6 additions & 5 deletions core/src/fr/hammons/slinc/modules/DescriptorModule.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package fr.hammons.slinc.modules

import fr.hammons.slinc.{Bytes, TypeDescriptor}
import fr.hammons.slinc.Bytes
import fr.hammons.slinc.ForeignTypeDescriptor

/** A module used to perform Platform dependent work with a descriptor
*/
trait DescriptorModule:
def memberOffsets(sd: List[TypeDescriptor]): IArray[Bytes]
def sizeOf(td: TypeDescriptor): Bytes
def alignmentOf(td: TypeDescriptor): Bytes
def toCarrierType(td: TypeDescriptor): Class[?]
def memberOffsets(sd: List[ForeignTypeDescriptor]): IArray[Bytes]
def sizeOf(td: ForeignTypeDescriptor): Bytes
def alignmentOf(td: ForeignTypeDescriptor): Bytes
def toCarrierType(td: ForeignTypeDescriptor): Class[?]
18 changes: 18 additions & 0 deletions core/src/fr/hammons/slinc/types/Basic.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
package fr.hammons.slinc.types

import fr.hammons.slinc.Transform

type CChar = Byte
type CShort = Short
type CInt = Int
type CFloat = Float
type CDouble = Double
type CLongLong = Long

opaque type CBool >: Boolean <: Boolean = Boolean

object CBool:
given Transform[CBool, Byte](
b => if b != (0: Byte) then true else false,
b => if b then 1: Byte else 0: Byte
)

opaque type CBoolShort >: Boolean <: Boolean = Boolean

object CBoolShort:
given Transform[CBoolShort, Short](
s => if s != (0: Short) then true else false,
b => if b then 1: Short else 0: Short
)
Loading

0 comments on commit 7089e46

Please sign in to comment.