From 580ef1a987a2032cbeaaa5b1b41cbeae7c23fbd4 Mon Sep 17 00:00:00 2001 From: Georgi Krastev Date: Mon, 31 May 2021 19:40:11 +0300 Subject: [PATCH] Optimize sized.ToHList and ToSizedHList * Use type parameters and `Aux` instead of path-dependent types * Optimize runtime by replacing direct recursion with `foldRight` --- .../src/main/scala/shapeless/ops/sizeds.scala | 35 ++++++++++++++----- .../shapeless/ops/traversables.scala | 14 ++++---- core/src/test/scala/shapeless/hlist.scala | 1 - 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/core/src/main/scala/shapeless/ops/sizeds.scala b/core/src/main/scala/shapeless/ops/sizeds.scala index 1b49da1bb..e832ad50f 100644 --- a/core/src/main/scala/shapeless/ops/sizeds.scala +++ b/core/src/main/scala/shapeless/ops/sizeds.scala @@ -17,6 +17,8 @@ package shapeless package ops +import shapeless.ops.hlist.Fill + object sized { /** * Type class supporting conversion of this `Sized` to an `HList` whose elements have the same type as in `Repr`. @@ -29,19 +31,34 @@ object sized { } object ToHList { - type Aux[Repr, L <: Nat, Out0 <: HList] = ToHList[Repr, L] { type Out = Out0 } + type Aux[-Repr, L <: Nat, O <: HList] = ToHList[Repr, L] { + type Out = O + } - implicit val emptySizedToHList: Aux[Any, Nat._0, HNil] = + @deprecated("Use instance instead", "2.3.8") + val emptySizedToHList: Aux[Any, Nat._0, HNil] = new ToHList[Any, Nat._0] { type Out = HNil - def apply(s: Sized[Any, Nat._0]) = HNil + def apply(s: Sized[Any, Nat._0]): HNil = HNil } - implicit def nonEmptySizedToHList[Repr, L <: Nat] - (implicit itl: IsRegularIterable[Repr], ev: AdditiveCollection[Repr], ts: ToHList[Repr, L]): Aux[Repr, Succ[L], itl.A :: ts.Out] = - new ToHList[Repr, Succ[L]] { - type Out = itl.A :: ts.Out - def apply(s: Sized[Repr, Succ[L]]) = s.head :: ts(s.tail) - } + @deprecated("Use instance instead", "2.3.8") + def nonEmptySizedToHList[Repr, L <: Nat]( + implicit itl: IsRegularIterable[Repr], + ev: AdditiveCollection[Repr], + ts: ToHList[Repr, L] + ): Aux[Repr, Succ[L], itl.A :: ts.Out] = new ToHList[Repr, Succ[L]] { + type Out = itl.A :: ts.Out + def apply(s: Sized[Repr, Succ[L]]): Out = s.head :: ts(s.tail) + } + + implicit def instance[Repr, T, N <: Nat, O <: HList]( + implicit itl: IsRegularIterable[Repr] { type A = T }, + fill: Fill.Aux[N, T, O] + ): Aux[Repr, N, O] = new ToHList[Repr, N] { + type Out = O + def apply(s: Sized[Repr, N]): O = + itl(s.unsized).foldRight[HList](HNil)(_ :: _).asInstanceOf[O] + } } } diff --git a/core/src/main/scala_2.13+/shapeless/ops/traversables.scala b/core/src/main/scala_2.13+/shapeless/ops/traversables.scala index d531e4683..7aa46599b 100644 --- a/core/src/main/scala_2.13+/shapeless/ops/traversables.scala +++ b/core/src/main/scala_2.13+/shapeless/ops/traversables.scala @@ -79,16 +79,14 @@ object traversable { type Out = Out0 } - implicit def instance[CC[T] <: Iterable[T], A, N <: Nat]( + implicit def instance[CC[T] <: Iterable[T], A, N <: Nat, O <: HList]( implicit gt: IsRegularIterable[CC[A]], ac: AdditiveCollection[CC[A]], ti: ToInt[N], - th: ToHList[CC[A], N] - ): Aux[CC, A, N, Option[th.Out]] = - new ToSizedHList[CC, A, N] { - type Out = Option[th.Out] - def apply(as: CC[A]): Out = - as.sized[N].map(_.toHList) - } + th: ToHList.Aux[CC[A], N, O] + ): Aux[CC, A, N, Option[O]] = new ToSizedHList[CC, A, N] { + type Out = Option[O] + def apply(as: CC[A]): Out = as.sized[N].map(th.apply) + } } } diff --git a/core/src/test/scala/shapeless/hlist.scala b/core/src/test/scala/shapeless/hlist.scala index 01cebd506..ce8f7d246 100644 --- a/core/src/test/scala/shapeless/hlist.scala +++ b/core/src/test/scala/shapeless/hlist.scala @@ -18,7 +18,6 @@ package shapeless import org.junit.Test import org.junit.Assert._ - import test._ import testutil._