Skip to content

Instantly share code, notes, and snippets.

@kitlangton
Created September 20, 2022 03:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kitlangton/0ce8cb031c1dca96f5b7c2d51e78c6cc to your computer and use it in GitHub Desktop.
Save kitlangton/0ce8cb031c1dca96f5b7c2d51e78c6cc to your computer and use it in GitHub Desktop.
package zio.http.api.internal
sealed trait Box[A] extends Product with Serializable { self =>
def zip[B](that: Box[B])(implicit zipper: Zipper[A, B]): Box[zipper.Out] =
Box.Zip[A, B, zipper.Out](self, that, zipper)
def map[B](f: A => B)(implicit tupleSize: TupleSize[B]): Box[B] =
Box.Map(self, f, tupleSize)
def tupleSize: Int = self match {
case Box.Zip(left, right, _) => left.tupleSize + right.tupleSize
case Box.Map(_, _, tupleSize) => tupleSize.size
case Box.Succeed(_, tupleSize) => tupleSize.size
}
}
object Box {
def succeed[A](value: A)(implicit size: TupleSize[A]): Box[A] = Succeed(value, size)
final case class Succeed[A](value: A, size: TupleSize[A]) extends Box[A]
final case class Zip[A, B, C](lhs: Box[A], rhs: Box[B], zipper: Zipper.WithOut[A, B, C]) extends Box[C]
final case class Map[A, B](box: Box[A], f: A => B, size: TupleSize[B]) extends Box[B]
def makeConstructor[A](box: Box[A]): Array[Any] => A = {
box match {
case Succeed(value, _) => _ => value
case zip @ Zip(_, _, _) =>
makeZipper(zip)
case Map(box, f, _) =>
val constructor = makeConstructor(box)
args => f(constructor(args))
}
}
private def makeZipper[A](box: Zip[_, _, A]): Array[Any] => A = {
if (countNestedZips(box) <= 2) {
// If there aren't enough nested zips, this optimization is not worth it,
// use the original implementation.
box match {
case Zip(lhs, rhs, zipper) =>
val leftConstructor = makeConstructor(lhs)
val rightConstructor = makeConstructor(rhs)
results => {
val leftValue = leftConstructor(results)
val rightValue = rightConstructor(results)
zipper.combine(leftValue, rightValue)
}
}
} else {
// If there 3 or more nested zips, we can optimize the zipper
val zipper = makeZipperImpl(box, 0)
val size = box.tupleSize
results => {
val array: Array[Any] = Array.ofDim(size)
zipper(results)(array)
arrayToTuple[A](array, size)
}
}
}
private def makeZipperImpl(box: Box[_], start: Int): Array[Any] => Array[Any] => Unit = {
box match {
case Zip(lhs, rhs, _) =>
val zipper1 = makeZipperImpl(lhs, start)
val zipper2 = makeZipperImpl(rhs, start + lhs.tupleSize)
results =>
builder => {
zipper1(results)(builder)
zipper2(results)(builder)
}
case map @ Map(_, _, tupleSize) =>
val constructor = makeConstructor(map)
results =>
builder => {
val result = constructor(results)
tupleSize.spread(result, builder, start)
}
case succeed @ Succeed(_, tupleSize) =>
val constructor = makeConstructor(succeed)
results =>
builder => {
val result = constructor(results)
tupleSize.spread(result, builder, start)
}
}
}
private def countNestedZips(box: Box[_]): Int =
box match {
case Zip(left, right, _) => 1 + countNestedZips(left) + countNestedZips(right)
case Map(_, _, _) => 0
case Succeed(_, _) => 0
}
private def arrayToTuple[A](array: Array[Any], size: Int): A = {
println(s"Converting array ${array.toList} to tuple of size $size")
size match {
case 1 => array(0).asInstanceOf[A]
case 2 => (array(0), array(1)).asInstanceOf[A]
case 3 => (array(0), array(1), array(2)).asInstanceOf[A]
case 4 => (array(0), array(1), array(2), array(3)).asInstanceOf[A]
case 5 => (array(0), array(1), array(2), array(3), array(4)).asInstanceOf[A]
case 6 => (array(0), array(1), array(2), array(3), array(4), array(5)).asInstanceOf[A]
case 7 => (array(0), array(1), array(2), array(3), array(4), array(5), array(6)).asInstanceOf[A]
case 8 => (array(0), array(1), array(2), array(3), array(4), array(5), array(6), array(7)).asInstanceOf[A]
}
}
}
object BoxExample extends App {
val example =
Box.succeed((10, ())) zip Box.succeed(2.0) zip Box.succeed(true) zip Box.succeed("b")
// val example: Box[(Int, String, Double)] =
// Box.succeed((1, "a")) zip Box.succeed(2.0)
val constructor = Box.makeConstructor(example)
val result = constructor(Array())
println(result)
}
sealed trait Zipper[A, B] extends Product with Serializable {
type Out
def combine(a: A, b: B): Out
}
object Zipper extends LowPriorityZipper1 {
type WithOut[A, B, Out0] = Zipper[A, B] { type Out = Out0 }
final case class Zipper2[A, B, C]() extends Zipper[(A, B), C] {
type Out = (A, B, C)
override def combine(a: (A, B), b: C): (A, B, C) = (a._1, a._2, b)
}
implicit def zipper2[A, B, C]: Zipper.WithOut[(A, B), C, (A, B, C)] = Zipper2()
final case class Zipper3[A, B, C, D]() extends Zipper[(A, B, C), D] {
type Out = (A, B, C, D)
override def combine(a: (A, B, C), b: D): (A, B, C, D) = (a._1, a._2, a._3, b)
}
implicit def zipper3[A, B, C, D]: Zipper.WithOut[(A, B, C), D, (A, B, C, D)] = Zipper3()
final case class Zipper4[A, B, C, D, E]() extends Zipper[(A, B, C, D), E] {
type Out = (A, B, C, D, E)
override def combine(a: (A, B, C, D), b: E): (A, B, C, D, E) = (a._1, a._2, a._3, a._4, b)
}
implicit def zipper4[A, B, C, D, E]: Zipper.WithOut[(A, B, C, D), E, (A, B, C, D, E)] = Zipper4()
}
trait LowPriorityZipper1 extends LowPriorityZipper0 {
implicit def leftUnitZipper[A]: Zipper.WithOut[Unit, A, A] = LowPriorityZipper1.LeftUnitZipper[A]()
implicit def rightUnitZipper[A]: Zipper.WithOut[A, Unit, A] = LowPriorityZipper1.RightUnitZipper[A]()
}
object LowPriorityZipper1 {
final case class LeftUnitZipper[A]() extends Zipper[Unit, A] {
type Out = A
override def combine(a: Unit, b: A): A = b
}
final case class RightUnitZipper[A]() extends Zipper[A, Unit] {
type Out = A
override def combine(a: A, b: Unit): A = a
}
}
trait TupleSize[A] {
def size: Int
def spread(value: A, array: Array[Any], start: Int): Unit
}
object TupleSize extends TupleSizeLowPri {
def apply[A](implicit ts: TupleSize[A]): TupleSize[A] = ts
implicit def unit: TupleSize[Unit] = new TupleSize[Unit] {
override def size: Int = 0
override def spread(value: Unit, array: Array[Any], start: Int): Unit = ()
}
implicit def tupleSize2[A, B]: TupleSize[(A, B)] = new TupleSize[(A, B)] {
def size: Int = 2
override def spread(value: (A, B), array: Array[Any], start: Int): Unit = {
array(start) = value._1
array(start + 1) = value._2
}
}
implicit def tupleSize3[A, B, C]: TupleSize[(A, B, C)] = new TupleSize[(A, B, C)] {
def size: Int = 3
override def spread(value: (A, B, C), array: Array[Any], start: Int): Unit = {
array(start) = value._1
array(start + 1) = value._2
array(start + 2) = value._3
}
}
implicit def tupleSize4[A, B, C, D]: TupleSize[(A, B, C, D)] = new TupleSize[(A, B, C, D)] {
def size: Int = 4
override def spread(value: (A, B, C, D), array: Array[Any], start: Int): Unit = {
array(start) = value._1
array(start + 1) = value._2
array(start + 2) = value._3
array(start + 3) = value._4
}
}
}
trait TupleSizeLowPri {
implicit def tupleSize[A]: TupleSize[A] = new TupleSize[A] {
def size: Int = 1
override def spread(value: A, array: Array[Any], start: Int): Unit = {
array(start) = value
}
}
}
trait LowPriorityZipper0 {
implicit def abZipper[A, B]: Zipper.WithOut[A, B, (A, B)] = LowPriorityZipper0.ABZipper[A, B]()
}
object LowPriorityZipper0 {
final case class ABZipper[A, B]() extends Zipper[A, B] {
type Out = (A, B)
override def combine(a: A, b: B): (A, B) = (a, b)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment