/
Adjacent.scala
64 lines (54 loc) · 1.63 KB
/
Adjacent.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package eu.timepit.refined.internal
/**
* Type class that provides the next greater or next smaller value for
* a given argument.
*/
trait Adjacent[T] extends Ordering[T] {
/**
* Returns the next greater value adjacent to `t` or `t` if there is
* no greater value.
*/
def nextUp(t: T): T
/**
* Returns the next smaller value adjacent to `t` or `t` if there is
* no smaller value.
*/
def nextDown(t: T): T
/**
* Returns the next greater value adjacent to `t` or `None` if there is
* no greater value.
*/
def nextUpOrNone(t: T): Option[T] = {
val n = nextUp(t)
if (gt(n, t)) Some(n) else None
}
/**
* Returns the next smaller value adjacent to `t` or `None` if there is
* no smaller value.
*/
def nextDownOrNone(t: T): Option[T] = {
val n = nextDown(t)
if (lt(n, t)) Some(n) else None
}
}
object Adjacent {
def apply[T](implicit at: Adjacent[T]): Adjacent[T] = at
def instance[T](compareF: (T, T) => Int, nextUpF: T => T, nextDownF: T => T): Adjacent[T] =
new Adjacent[T] {
override def compare(x: T, y: T): Int = compareF(x, y)
override def nextUp(t: T): T = nextUpF(t)
override def nextDown(t: T): T = nextDownF(t)
}
implicit val doubleAdjacent: Adjacent[Double] =
instance(Ordering.Double.compare, Math.nextUp, Math.nextDown)
implicit val floatAdjacent: Adjacent[Float] =
instance(Ordering.Float.compare, Math.nextUp, Math.nextDown)
implicit def integralAdjacent[T](
implicit it: Integral[T]
): Adjacent[T] =
instance(
it.compare,
t => it.max(it.plus(t, it.one), t),
t => it.min(it.minus(t, it.one), t)
)
}