Skip to content

Commit

Permalink
more instances for Hash (#1712): Queue/Duration (#1950)
Browse files Browse the repository at this point in the history
* more instances to Hash: Queue/Duration

* more instances to Hash: Queue/Duration
  • Loading branch information
ctongfei authored and kailuowang committed Oct 6, 2017
1 parent c131fe4 commit 4ffd3a1
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 41 deletions.
5 changes: 5 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 @@ -111,10 +111,12 @@ class LawTests extends FunSuite with Discipline {
laws[HashLaws, BigDecimal].check(_.hash)
laws[HashLaws, BigInt].check(_.hash)
laws[HashLaws, UUID].check(_.hash)
laws[HashLaws, Duration].check(_.hash)
laws[HashLaws, List[Int]].check(_.hash)
laws[HashLaws, Option[String]].check(_.hash)
laws[HashLaws, List[String]].check(_.hash)
laws[HashLaws, Vector[Int]].check(_.hash)
laws[HashLaws, Queue[Int]].check(_.hash)
laws[HashLaws, Stream[Int]].check(_.hash)
laws[HashLaws, Set[Int]].check(_.hash)
laws[HashLaws, (Int, String)].check(_.hash)
Expand All @@ -139,6 +141,7 @@ class LawTests extends FunSuite with Discipline {
laws[HashLaws, List[Int]].check(_.sameAsUniversalHash)
laws[HashLaws, Option[String]].check(_.sameAsUniversalHash)
laws[HashLaws, List[String]].check(_.sameAsUniversalHash)
laws[HashLaws, Queue[Int]].check(_.sameAsUniversalHash)
laws[HashLaws, Vector[Int]].check(_.sameAsUniversalHash)
laws[HashLaws, Stream[Int]].check(_.sameAsUniversalHash)
laws[HashLaws, Set[Int]].check(_.sameAsUniversalHash)
Expand All @@ -160,11 +163,13 @@ class LawTests extends FunSuite with Discipline {
laws[HashLaws, BigDecimal].check(_.sameAsScalaHashing)
laws[HashLaws, BigInt].check(_.sameAsScalaHashing)
laws[HashLaws, UUID].check(_.sameAsScalaHashing)
laws[HashLaws, Duration].check(_.sameAsScalaHashing)

laws[HashLaws, Option[HasHash[Int]]].check(_.hash)
laws[HashLaws, List[HasHash[Int]]].check(_.hash)
laws[HashLaws, Vector[HasHash[Int]]].check(_.hash)
laws[HashLaws, Stream[HasHash[Int]]].check(_.hash)
laws[HashLaws, Queue[HasHash[Int]]].check(_.hash)

laws[OrderLaws, List[HasEq[Int]]].check(_.eqv)
laws[OrderLaws, Option[HasEq[Int]]].check(_.eqv)
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 4ffd3a1

Please sign in to comment.