Skip to content

Commit

Permalink
Add BoundlessEnumerable, nextOrMin, and previousOrMax
Browse files Browse the repository at this point in the history
  • Loading branch information
isomarcte committed Nov 17, 2022
1 parent bbd6664 commit be74ffc
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 6 deletions.
4 changes: 4 additions & 0 deletions kernel/src/main/scala-2.12/cats/kernel/EnumerableCompat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ package kernel
import scala.{specialized => sp}
import scala.collection.immutable.Stream

@deprecated(message = "Please use Enumerable instead.", since = "2.10.0")
trait PartialPreviousUpperBounded[@sp A] extends PartialPrevious[A] with PartialNext[A] with UpperBounded[A] {

/**
* Enumerate the members in descending order.
*/
@deprecated(message = "Please use Enumerable.membersDescending.", since = "2.10.0")
def membersDescending: Stream[A] = {
def loop(a: A): Stream[A] =
partialPrevious(a) match {
Expand All @@ -41,11 +43,13 @@ trait PartialPreviousUpperBounded[@sp A] extends PartialPrevious[A] with Partial

}

@deprecated(message = "Please use Enumerable instead.", since = "2.10.0")
trait PartialNextLowerBounded[@sp A] extends PartialPrevious[A] with PartialNext[A] with LowerBounded[A] {

/**
* Enumerate the members in ascending order.
*/
@deprecated(message = "Please use Enumerable.membersAscending.", since = "2.10.0")
def membersAscending: Stream[A] = {
def loop(a: A): Stream[A] =
partialNext(a) match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ package kernel
import scala.{specialized => sp}
import scala.collection.immutable.LazyList

@deprecated(message = "Please use Enumerable", since = "2.10.0")
trait PartialPreviousUpperBounded[@sp A] extends PartialPrevious[A] with PartialNext[A] with UpperBounded[A] {

/**
* Enumerate the members in descending order.
*/
@deprecated(message = "Please use Enumerable.membersDescending.", since = "2.10.0")
def membersDescending: LazyList[A] = {
def loop(a: A): LazyList[A] =
partialPrevious(a) match {
Expand All @@ -41,11 +43,13 @@ trait PartialPreviousUpperBounded[@sp A] extends PartialPrevious[A] with Partial

}

@deprecated(message = "Please use Enumerable", since = "2.10.0")
trait PartialNextLowerBounded[@sp A] extends PartialPrevious[A] with PartialNext[A] with LowerBounded[A] {

/**
* Enumerate the members in ascending order.
*/
@deprecated(message = "Please use Enumerable.membersAscending.", since = "2.10.0")
def membersAscending: LazyList[A] = {
def loop(a: A): LazyList[A] =
partialNext(a) match {
Expand Down
49 changes: 44 additions & 5 deletions kernel/src/main/scala/cats/kernel/Enumerable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import cats.kernel.{ScalaVersionSpecificLazyListCompat => LazyListLike}
trait Enumerable[@sp A] extends PartialNext[A] with PartialPrevious[A]{
def order: Order[A]
def fromEnum(a: A): BigInt
def toEnum(i: BigInt): Option[A]
def toEnumOpt(i: BigInt): Option[A]

/** The fundamental function in the `Enumerable` class. Given a `first`
* element, a second element, and an optional `last` element, enumerate the
Expand Down Expand Up @@ -128,7 +128,7 @@ trait Enumerable[@sp A] extends PartialNext[A] with PartialPrevious[A]{
}

def enumFromByToOpt(first: A, step: BigInt, last: Option[A]): LazyListLike.T[A] =
toEnum(step).fold(
toEnumOpt(step).fold(
LazyListLike.empty[A]
)(second =>
enumFromThenToOpt(first, second, last)
Expand Down Expand Up @@ -204,6 +204,20 @@ trait Enumerable[@sp A] extends PartialNext[A] with PartialPrevious[A]{
LazyListLike(first)
}

def membersDescending(implicit A: UpperBounded[A]): LazyListLike.T[A] =
partialPrevious(A.maxBound).fold(
LazyListLike.empty[A]
)(previous =>
enumFromThen(A.maxBound, previous)
)

def membersAscending(implicit A: LowerBounded[A]): LazyListLike.T[A] =
partialNext(A.minBound).fold(
LazyListLike.empty[A]
)(next =>
enumFromThen(A.minBound, next)
)

override final def partialOrder: PartialOrder[A] = order
}

Expand Down Expand Up @@ -238,6 +252,9 @@ trait PartialNext[@sp A] {

loop(a, n)
}

def nextOrMin(a: A)(implicit A: LowerBounded[A]): A =
partialNext(a).getOrElse(A.minBound)
}

/**
Expand All @@ -246,6 +263,10 @@ trait PartialNext[@sp A] {
*/
trait Next[@sp A] extends PartialNext[A] {
def next(a: A): A

override final def nextOrMin(a: A)(implicit A: LowerBounded[A]): A =
next(a)

override def partialNext(a: A): Option[A] = Some(next(a))
}

Expand Down Expand Up @@ -276,6 +297,9 @@ trait PartialPrevious[@sp A] {

loop(a, n)
}

def previousOrMax(a: A)(implicit A: UpperBounded[A]): A =
partialPrevious(a).getOrElse(A.maxBound)
}

/**
Expand All @@ -285,29 +309,44 @@ trait PartialPrevious[@sp A] {
trait Previous[@sp A] extends PartialPrevious[A] {
def partialOrder: PartialOrder[A]
def previous(a: A): A

override final def previousOrMax(a: A)(implicit A: UpperBounded[A]): A =
previous(a)

override def partialPrevious(a: A): Option[A] = Some(previous(a))
}

/**
* A typeclass which has both `previous` and `next` operations
* such that `next . previous == identity`.
*/
// TODO: Not sure what to do about UnboundedEnumerable. It should extend
// Enumerable, but we can't do that without breaking
// bincompat. BoundlessEnumerable could extened UnboundedEnumerable, but that
// seems silly...
trait UnboundedEnumerable[@sp A] extends Next[A] with Previous[A] {
def order: Order[A]
override def partialOrder: PartialOrder[A] = order
}

trait BoundlessEnumerable[@sp A] extends Enumerable[A] with Next[A] with Previous[A] {
def toEnum(i: BigInt): A

override final def toEnumOpt(i: BigInt): Option[A] = Some(toEnum(i))
}

trait BoundedEnumerable[@sp A] extends PartialPreviousUpperBounded[A] with PartialNextLowerBounded[A] {

def order: Order[A]
override def partialOrder: PartialOrder[A] = order

@deprecated(message = "Please use nextOrMin instead.", since = "2.10.0")
def cycleNext(a: A): A =
partialNext(a).getOrElse(minBound)
nextOrMin(a)(this)

@deprecated(message = "Please use previousOrMax instead.", since = "2.10.0")
def cyclePrevious(a: A): A =
partialPrevious(a).getOrElse(maxBound)

previousOrMax(a)(this)
}

object BoundedEnumerable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class IntOrder extends Order[Int] with Hash[Int] with IntBounded with IntEnumera
override val order: Order[Int] = self

override final def fromEnum(a: Int): BigInt = BigInt(a)
override final def toEnum(i: BigInt): Option[Int] =
override final def toEnumOpt(i: BigInt): Option[Int] =
if (i <= BigInt(Int.MaxValue) || i >= BigInt(Int.MinValue)) {
Some(i.toInt)
} else {
Expand Down

0 comments on commit be74ffc

Please sign in to comment.