Skip to content

Commit

Permalink
Merge branch 'master' into make-kernel-laws-consistent
Browse files Browse the repository at this point in the history
  • Loading branch information
Luka Jacobowitz committed Oct 6, 2017
2 parents 1ca0ecd + 4ffd3a1 commit 668c4e1
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 41 deletions.
2 changes: 2 additions & 0 deletions kernel-laws/src/test/scala/cats/kernel/laws/LawTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ class LawTests extends FunSuite with Discipline {
checkAll("Hash[Short]" , HashTests[Short].hash)
checkAll("Hash[Char]" , HashTests[Char].hash)
checkAll("Hash[Int]" , HashTests[Int].hash)
checkAll("Hash[Duration]", HashTests[Duration].hash)

// NOTE: Do not test for Float/Double/Long. These types'
// `##` is different from `hashCode`. See [[scala.runtime.Statics.anyHash]].
Expand All @@ -207,6 +208,7 @@ class LawTests extends FunSuite with Discipline {
checkAll("Hash[(Int, String)]" , HashTests[(Int, String)].hash)
checkAll("Hash[Either[Int, String]]" , HashTests[Either[Int, String]].hash)
checkAll("Hash[Map[Int, String]]" , HashTests[Map[Int, String]].hash)
checkAll("Hash[Queue[Int]", HashTests[Queue[Int]].hash)



Expand Down
30 changes: 30 additions & 0 deletions kernel/src/main/scala/cats/kernel/instances/StaticMethods.scala
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,34 @@ object StaticMethods {
h = mix(h, _2Hash)
finalizeHash(h, 2)
}

// adapted from [[scala.util.hashing.MurmurHash3]],
// but modified standard `Any#hashCode` to `ev.hash`.
def listHash[A](x: List[A])(implicit A: Hash[A]): Int = {
import scala.util.hashing.MurmurHash3._
var n = 0
var h = seqSeed
var elems = x
while (!elems.isEmpty) {
val head = elems.head
val tail = elems.tail
h = mix(h, A.hash(head))
n += 1
elems = tail
}
finalizeHash(h, n)
}

// adapted from scala.util.hashing.MurmurHash3
def orderedHash[A](xs: TraversableOnce[A])(implicit A: Hash[A]): Int = {
import scala.util.hashing.MurmurHash3._
var n = 0
var h = seqSeed
xs foreach { x =>
h = mix(h, A.hash(x))
n += 1
}
finalizeHash(h, n)
}

}
6 changes: 4 additions & 2 deletions kernel/src/main/scala/cats/kernel/instances/duration.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import scala.concurrent.duration.Duration
package object duration extends DurationInstances

trait DurationInstances {
implicit val catsKernelStdOrderForDuration: Order[Duration] = new DurationOrder
implicit val catsKernelStdOrderForDuration: Order[Duration] with Hash[Duration] = new DurationOrder
implicit val catsKernelStdGroupForDuration: CommutativeGroup[Duration] = new DurationGroup
}

Expand All @@ -18,7 +18,9 @@ trait DurationInstances {
* The value Duration.Undefined breaks our laws, because undefined
* values are not equal to themselves.
*/
class DurationOrder extends Order[Duration] {
class DurationOrder extends Order[Duration] with Hash[Duration] {
def hash(x: Duration): Int = x.hashCode()

def compare(x: Duration, y: Duration): Int = x compare y

override def eqv(x: Duration, y: Duration): Boolean = x == y
Expand Down
17 changes: 1 addition & 16 deletions kernel/src/main/scala/cats/kernel/instances/list.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,22 +62,7 @@ class ListPartialOrder[A](implicit ev: PartialOrder[A]) extends PartialOrder[Lis
}

class ListHash[A](implicit ev: Hash[A]) extends ListEq[A]()(ev) with Hash[List[A]] {
// adapted from [[scala.util.hashing.MurmurHash3]],
// but modified standard `Any#hashCode` to `ev.hash`.
import scala.util.hashing.MurmurHash3._
def hash(x: List[A]): Int = {
var n = 0
var h = seqSeed
var elems = x
while (!elems.isEmpty) {
val head = elems.head
val tail = elems.tail
h = mix(h, ev.hash(head))
n += 1
elems = tail
}
finalizeHash(h, n)
}
def hash(x: List[A]): Int = StaticMethods.listHash(x)(ev)
}

class ListEq[A](implicit ev: Eq[A]) extends Eq[List[A]] {
Expand Down
7 changes: 7 additions & 0 deletions kernel/src/main/scala/cats/kernel/instances/queue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ trait QueueInstances extends QueueInstances1 {
trait QueueInstances1 extends QueueInstances2 {
implicit def catsKernelStdPartialOrderForQueue[A: PartialOrder]: PartialOrder[Queue[A]] =
new QueuePartialOrder[A]

implicit def catsKernelStdHashForQueue[A: Hash]: Hash[Queue[A]] =
new QueueHash[A]
}

trait QueueInstances2 {
Expand All @@ -28,6 +31,10 @@ class QueueOrder[A](implicit ev: Order[A]) extends Order[Queue[A]] {
else StaticMethods.iteratorCompare(xs.iterator, ys.iterator)
}

class QueueHash[A](implicit ev: Hash[A]) extends QueueEq[A] with Hash[Queue[A]] {
def hash(x: Queue[A]): Int = StaticMethods.orderedHash(x)
}

class QueuePartialOrder[A](implicit ev: PartialOrder[A]) extends PartialOrder[Queue[A]] {
def partialCompare(xs: Queue[A], ys: Queue[A]): Double =
if (xs eq ys) 0.0
Expand Down
12 changes: 1 addition & 11 deletions kernel/src/main/scala/cats/kernel/instances/stream.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,7 @@ class StreamPartialOrder[A](implicit ev: PartialOrder[A]) extends PartialOrder[S
}

class StreamHash[A](implicit ev: Hash[A]) extends StreamEq[A]()(ev) with Hash[Stream[A]] {
import scala.util.hashing.MurmurHash3._
// adapted from scala.util.hashing.MurmurHash3
def hash(xs: Stream[A]): Int = {
var n = 0
var h = seqSeed
xs foreach { x =>
h = mix(h, ev.hash(x))
n += 1
}
finalizeHash(h, n)
}
def hash(xs: Stream[A]): Int = StaticMethods.orderedHash(xs)
}

class StreamEq[A](implicit ev: Eq[A]) extends Eq[Stream[A]] {
Expand Down
14 changes: 2 additions & 12 deletions kernel/src/main/scala/cats/kernel/instances/vector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,8 @@ class VectorPartialOrder[A](implicit ev: PartialOrder[A]) extends PartialOrder[V
else StaticMethods.iteratorPartialCompare(xs.iterator, ys.iterator)
}

class VectorHash[A](implicit ev: Hash[A]) extends VectorEq[A]()(ev) with Hash[Vector[A]] {
// adapted from scala.util.hashing
import scala.util.hashing.MurmurHash3._
def hash(xs: Vector[A]): Int = {
var n = 0
var h = seqSeed
xs foreach { x =>
h = mix(h, ev.hash(x))
n += 1
}
finalizeHash(h, n)
}
class VectorHash[A](implicit ev: Hash[A]) extends VectorEq[A] with Hash[Vector[A]] {
def hash(xs: Vector[A]): Int = StaticMethods.orderedHash(xs)
}

class VectorEq[A](implicit ev: Eq[A]) extends Eq[Vector[A]] {
Expand Down

0 comments on commit 668c4e1

Please sign in to comment.