Created
September 20, 2022 03:36
-
-
Save kitlangton/0ce8cb031c1dca96f5b7c2d51e78c6cc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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