Skip to content

Commit

Permalink
Merge pull request #9 from LibreCybernetics/perf
Browse files Browse the repository at this point in the history
performance changes
  • Loading branch information
fabianhjr authored Sep 3, 2023
2 parents 98a8452 + 9404d01 commit cf06b2a
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,5 @@ trait Bijection[F[_, _], A, B]:
def flip: F[B, A]

// Combine
def ++[
M[_]: [M[_]] =>> MonadError[M, Bijection.Error]
](other: F[A, B]): M[F[A, B]]
def ++(other: F[A, B]): F[A, B]
end Bijection
46 changes: 13 additions & 33 deletions core/src/main/scala/dev/librecybernetics/data/FnBijection.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,25 @@ import cats.MonadError
case class FnBijection[A, B](
forwardFn: A => B,
reverseFn: B => A
) extends Bijection[FnBijection, A, B]:
) extends Bijection[FnBijection, A, B] { self =>
// Properties
def isDefined(a: A): Boolean = Try(forwardFn(a)).isSuccess

// Access
def apply(a: A): Option[B] = Try(forwardFn(a)).toOption
def apply(a: A): Option[B] = Try(forwardFn(a)).toOption

def reverse(b: B): Option[A] = Try(reverseFn(b)).toOption

// Transform
def flip: FnBijection[B, A] = FnBijection(reverseFn, forwardFn)
override lazy val flip: FnBijection[B, A] = new FnBijection(self.reverseFn, self.forwardFn) {
override lazy val flip: FnBijection[A, B] = self
}

// Combine
@SuppressWarnings(Array("org.wartremover.warts.Throw"))
def ++[F[_]: [F[_]] =>> MonadError[F, Bijection.Error]](
other: FnBijection[A, B]
): F[FnBijection[A, B]] =
MonadError[F, Bijection.Error].pure {
FnBijection(
forwardFn = a =>
(apply(a), other(a)) match
case (Some(b), None) => b
case (None, Some(b)) => b

case (Some(b1), Some(b2)) if b1 == b2 => b1

case (_, _) =>
throw new NoSuchElementException()
end match
,
reverseFn = b =>
(reverse(b), other.reverse(b)) match
case (Some(a), None) => a
case (None, Some(a)) => a

case (Some(a1), Some(a2)) if a1 == a2 => a1

case (_, _) =>
throw new NoSuchElementException()
end match
)
}
end FnBijection
@SuppressWarnings(Array("org.wartremover.warts.OptionPartial"))
def ++(other: FnBijection[A, B]): FnBijection[A, B] =
FnBijection(
forwardFn = a => other.apply(a).orElse(this.apply(a)).get,
reverseFn = b => other.reverse(b).orElse(this.reverse(b)).get
)
}
17 changes: 11 additions & 6 deletions core/src/main/scala/dev/librecybernetics/data/MapBijection.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import cats.{MonadError, Traverse}
case class MapBijection[A, B] private[data] (
forwardMap: Map[A, B],
reverseMap: Map[B, A]
) extends Bijection[MapBijection, A, B]:
) extends Bijection[MapBijection, A, B] { self =>

// Properties
override def isDefined(a: A): Boolean = forwardMap.contains(a)
Expand All @@ -31,11 +31,13 @@ case class MapBijection[A, B] private[data] (
end size

// Access
override def apply(a: A): Option[B] = forwardMap.get(a)
override def apply(a: A): Option[B] = forwardMap.get(a)

override def reverse(b: B): Option[A] = reverseMap.get(b)

def iterable: Iterable[(A, B)] = forwardMap.iterator.to(Iterable)
def keySet: Set[A] = forwardMap.keySet

def keySet: Set[A] = forwardMap.keySet

// Transform
override def flip: MapBijection[B, A] = new MapBijection[B, A](reverseMap, forwardMap)
Expand Down Expand Up @@ -70,8 +72,11 @@ case class MapBijection[A, B] private[data] (
): F[MapBijection[A, B]] =
Traverse[T].foldM(iterable, this)(_ + _)

override def ++[F[_]: [F[_]] =>> MonadError[F, Bijection.Error]](other: MapBijection[A, B]): F[MapBijection[A, B]] =
this ++ other.iterable
override def ++(other: MapBijection[A, B]): MapBijection[A, B] =
MapBijection(
forwardMap ++ other.forwardMap,
reverseMap ++ other.reverseMap
)
end ++

@targetName("remove")
Expand All @@ -83,7 +88,7 @@ case class MapBijection[A, B] private[data] (
@targetName("removeAll")
infix def --(i: IterableOnce[A]): MapBijection[A, B] =
i.iterator.foldLeft(this)(_ - _)
end MapBijection
}

object MapBijection:
def empty[A, B]: MapBijection[A, B] =
Expand Down
44 changes: 11 additions & 33 deletions core/src/main/scala/dev/librecybernetics/data/PFnBijection.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,24 @@ import cats.MonadError
case class PFnBijection[A, B](
forwardPFn: PartialFunction[A, B],
reversePFn: PartialFunction[B, A]
) extends Bijection[PFnBijection, A, B]:
) extends Bijection[PFnBijection, A, B] { self =>
// Properties
override def isDefined(a: A): Boolean = forwardPFn.isDefinedAt(a)

// Access
override def apply(a: A): Option[B] = forwardPFn.unapply(a)
override def reverse(b: B): Option[A] = reversePFn.unapply(b)
inline override def apply(a: A): Option[B] = forwardPFn.unapply(a)

inline override def reverse(b: B): Option[A] = reversePFn.unapply(b)

// Transform
override def flip: PFnBijection[B, A] = PFnBijection(reversePFn, forwardPFn)
override lazy val flip: PFnBijection[B, A] = new PFnBijection(reversePFn, forwardPFn) {
override lazy val flip: PFnBijection[A, B] = self
}

// Combine
override def ++[F[_]: [F[_]] =>> MonadError[F, Bijection.Error]](
other: PFnBijection[A, B]
): F[PFnBijection[A, B]] = MonadError[F, Bijection.Error].pure {
override def ++(other: PFnBijection[A, B]): PFnBijection[A, B] =
PFnBijection[A, B](
forwardPFn = {
case a if apply(a).isDefined && other(a).isEmpty =>
forwardPFn(a)
case a if apply(a).isEmpty && other(a).isDefined =>
other.forwardPFn(a)

case a
if apply(a).isDefined &&
other(a).isDefined &&
apply(a) == other(a) =>
forwardPFn(a)
}: PartialFunction[A, B],
reversePFn = {
case b if reverse(b).isDefined && other.reverse(b).isEmpty =>
reversePFn(b)
case b if reverse(b).isEmpty && other.reverse(b).isDefined =>
other.reversePFn(b)

case b
if reverse(b).isDefined &&
other.reverse(b).isDefined &&
reverse(b) == other.reverse(b) =>
reversePFn(b)
}: PartialFunction[B, A]
forwardPFn = other.forwardPFn.orElse(this.forwardPFn),
reversePFn = other.reversePFn.orElse(this.reversePFn)
)
}
end PFnBijection
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ class MapBijectionSpec extends AnyWordSpec:

val Right(secondBijection): Either[Bijection.Error, MapBijection[Char, Int]] =
MapBijection('d' -> 4, 'e' -> 5, 'f' -> 6): @unchecked
val Right(concat): Either[Bijection.Error, MapBijection[Char, Int]] =
bijection ++ secondBijection: @unchecked

val concat: MapBijection[Char, Int] = bijection ++ secondBijection
concat.size shouldBe 6
}

Expand Down

0 comments on commit cf06b2a

Please sign in to comment.