diff --git a/core/src/main/scala-2.12-/cats/instances/all.scala b/core/src/main/scala-2.12-/cats/instances/all.scala index 02dddee872..b67a56c8ac 100644 --- a/core/src/main/scala-2.12-/cats/instances/all.scala +++ b/core/src/main/scala-2.12-/cats/instances/all.scala @@ -50,3 +50,5 @@ private[cats] trait AllInstancesBinCompat3 extends AllCoreDurationInstances private[cats] trait AllInstancesBinCompat4 extends SortedMapInstancesBinCompat1 with MapInstancesBinCompat1 private[cats] trait AllInstancesBinCompat5 extends SortedSetInstancesBinCompat0 + +private[cats] trait AllInstancesBinCompat6 extends SortedSetInstancesBinCompat1 with SortedMapInstancesBinCompat2 diff --git a/core/src/main/scala-2.12-/cats/instances/package.scala b/core/src/main/scala-2.12-/cats/instances/package.scala index c171490fbb..0805b3ad56 100644 --- a/core/src/main/scala-2.12-/cats/instances/package.scala +++ b/core/src/main/scala-2.12-/cats/instances/package.scala @@ -9,6 +9,7 @@ package object instances { with AllInstancesBinCompat3 with AllInstancesBinCompat4 with AllInstancesBinCompat5 + with AllInstancesBinCompat6 object bigInt extends BigIntInstances object bigDecimal extends BigDecimalInstances object bitSet extends BitSetInstances @@ -38,8 +39,12 @@ package object instances { object queue extends QueueInstances object set extends SetInstances object short extends ShortInstances - object sortedMap extends SortedMapInstances with SortedMapInstancesBinCompat0 with SortedMapInstancesBinCompat1 - object sortedSet extends SortedSetInstances with SortedSetInstancesBinCompat0 + object sortedMap + extends SortedMapInstances + with SortedMapInstancesBinCompat0 + with SortedMapInstancesBinCompat1 + with SortedMapInstancesBinCompat2 + object sortedSet extends SortedSetInstances with SortedSetInstancesBinCompat0 with SortedSetInstancesBinCompat1 object stream extends StreamInstances with StreamInstancesBinCompat0 object string extends StringInstances object try_ extends TryInstances diff --git a/core/src/main/scala-2.13+/cats/instances/all.scala b/core/src/main/scala-2.13+/cats/instances/all.scala index b0220e3ee4..9524d80617 100644 --- a/core/src/main/scala-2.13+/cats/instances/all.scala +++ b/core/src/main/scala-2.13+/cats/instances/all.scala @@ -51,3 +51,5 @@ private[cats] trait AllInstancesBinCompat3 extends AllCoreDurationInstances private[cats] trait AllInstancesBinCompat4 extends SortedMapInstancesBinCompat1 with MapInstancesBinCompat1 private[cats] trait AllInstancesBinCompat5 extends SortedSetInstancesBinCompat0 + +private[cats] trait AllInstancesBinCompat6 extends SortedSetInstancesBinCompat1 with SortedMapInstancesBinCompat2 diff --git a/core/src/main/scala-2.13+/cats/instances/package.scala b/core/src/main/scala-2.13+/cats/instances/package.scala index fa49782947..6fb10eec1f 100644 --- a/core/src/main/scala-2.13+/cats/instances/package.scala +++ b/core/src/main/scala-2.13+/cats/instances/package.scala @@ -9,6 +9,7 @@ package object instances { with AllInstancesBinCompat3 with AllInstancesBinCompat4 with AllInstancesBinCompat5 + with AllInstancesBinCompat6 object bigInt extends BigIntInstances object bigDecimal extends BigDecimalInstances object bitSet extends BitSetInstances @@ -38,8 +39,12 @@ package object instances { object queue extends QueueInstances object set extends SetInstances object short extends ShortInstances - object sortedMap extends SortedMapInstances with SortedMapInstancesBinCompat0 with SortedMapInstancesBinCompat1 - object sortedSet extends SortedSetInstances with SortedSetInstancesBinCompat0 + object sortedMap + extends SortedMapInstances + with SortedMapInstancesBinCompat0 + with SortedMapInstancesBinCompat1 + with SortedMapInstancesBinCompat2 + object sortedSet extends SortedSetInstances with SortedSetInstancesBinCompat0 with SortedSetInstancesBinCompat1 @deprecated("2.0.0-RC2", "Use cats.instances.lazyList") object stream extends StreamInstances with StreamInstancesBinCompat0 diff --git a/core/src/main/scala/cats/instances/sortedMap.scala b/core/src/main/scala/cats/instances/sortedMap.scala index 555dcf04a4..8ed33c47d7 100644 --- a/core/src/main/scala/cats/instances/sortedMap.scala +++ b/core/src/main/scala/cats/instances/sortedMap.scala @@ -2,19 +2,19 @@ package cats.instances import cats.{Always, Applicative, Eval, FlatMap, Foldable, Monoid, MonoidK, Order, Show, Traverse, TraverseFilter} import cats.kernel._ -import cats.kernel.instances.StaticMethods import scala.annotation.tailrec import scala.collection.immutable.SortedMap trait SortedMapInstances extends SortedMapInstances2 { - implicit def catsStdHashForSortedMap[K: Hash: Order, V: Hash]: Hash[SortedMap[K, V]] = - new SortedMapHash[K, V] + @deprecated("2.0.0-RC2", "Use cats.kernel.instances.sortedMap.catsKernelStdHashForSortedMap") + private[instances] def catsStdHashForSortedMap[K: Hash: Order, V: Hash]: Hash[SortedMap[K, V]] = + cats.kernel.instances.sortedMap.catsKernelStdHashForSortedMap[K, V] - implicit def catsStdCommutativeMonoidForSortedMap[K: Order, V: CommutativeSemigroup] - : CommutativeMonoid[SortedMap[K, V]] = - new SortedMapCommutativeMonoid[K, V] + @deprecated("2.0.0-RC2", "Use cats.kernel.instances.sortedMap.catsKernelStdCommutativeMonoidForSortedMap") + private[instances] def catsStdCommutativeMonoidForSortedMap[K: Order, V: CommutativeSemigroup] = + cats.kernel.instances.sortedMap.catsKernelStdCommutativeMonoidForSortedMap[K, V] implicit def catsStdShowForSortedMap[A: Order, B](implicit showA: Show[A], showB: Show[B]): Show[SortedMap[A, B]] = new Show[SortedMap[A, B]] { @@ -114,76 +114,39 @@ trait SortedMapInstances extends SortedMapInstances2 { } private[instances] trait SortedMapInstances1 { - implicit def catsStdEqForSortedMap[K: Order, V: Eq]: Eq[SortedMap[K, V]] = + @deprecated("2.0.0-RC2", "Use cats.kernel.instances.sortedMap.catsKernelStdEqForSortedMap") + private[instances] def catsStdEqForSortedMap[K: Order, V: Eq]: Eq[SortedMap[K, V]] = new SortedMapEq[K, V] } private[instances] trait SortedMapInstances2 extends SortedMapInstances1 { - implicit def catsStdMonoidForSortedMap[K: Order, V: Semigroup]: Monoid[SortedMap[K, V]] = + @deprecated("2.0.0-RC2", "Use cats.kernel.instances.sortedMap.catsKernelStdMonoidForSortedMap") + private[instances] def catsStdMonoidForSortedMap[K: Order, V: Semigroup]: Monoid[SortedMap[K, V]] = new SortedMapMonoid[K, V] } +@deprecated("2.0.0-RC2", "Use cats.kernel.instances.SortedMapHash") class SortedMapHash[K, V](implicit V: Hash[V], O: Order[K], K: Hash[K]) - extends SortedMapEq[K, V]()(V, O) + extends SortedMapEq[K, V] with Hash[SortedMap[K, V]] { - // adapted from [[scala.util.hashing.MurmurHash3]], - // but modified standard `Any#hashCode` to `ev.hash`. - import scala.util.hashing.MurmurHash3._ - def hash(x: SortedMap[K, V]): Int = { - var a, b, n = 0 - var c = 1 - x.foreach { - case (k, v) => - val h = StaticMethods.product2HashWithPrefix(K.hash(k), V.hash(v), "Tuple2") - a += h - b ^= h - c = StaticMethods.updateUnorderedHashC(c, h) - n += 1 - } - var h = mapSeed - h = mix(h, a) - h = mix(h, b) - h = mixLast(h, c) - finalizeHash(h, n) - } + private[this] val underlying: Hash[SortedMap[K, V]] = new cats.kernel.instances.SortedMapHash[K, V] + def hash(x: SortedMap[K, V]): Int = underlying.hash(x) } -class SortedMapEq[K, V](implicit V: Eq[V], O: Order[K]) extends Eq[SortedMap[K, V]] { - def eqv(x: SortedMap[K, V], y: SortedMap[K, V]): Boolean = - if (x eq y) true - else - x.size == y.size && x.forall { - case (k, v1) => - y.get(k) match { - case Some(v2) => V.eqv(v1, v2) - case None => false - } - } -} +@deprecated("2.0.0-RC2", "Use cats.kernel.instances.SortedMapEq") +class SortedMapEq[K, V](implicit V: Eq[V], O: Order[K]) extends cats.kernel.instances.SortedMapEq[K, V] +@deprecated("2.0.0-RC2", "Use cats.kernel.instances.SortedMapCommutativeMonoid") class SortedMapCommutativeMonoid[K, V](implicit V: CommutativeSemigroup[V], O: Order[K]) extends SortedMapMonoid[K, V] - with CommutativeMonoid[SortedMap[K, V]] - -class SortedMapMonoid[K, V](implicit V: Semigroup[V], O: Order[K]) extends Monoid[SortedMap[K, V]] { - - def empty: SortedMap[K, V] = SortedMap.empty(O.toOrdering) - - def combine(xs: SortedMap[K, V], ys: SortedMap[K, V]): SortedMap[K, V] = - if (xs.size <= ys.size) { - xs.foldLeft(ys) { - case (my, (k, x)) => - my.updated(k, Semigroup.maybeCombine(x, my.get(k))) - } - } else { - ys.foldLeft(xs) { - case (mx, (k, y)) => - mx.updated(k, Semigroup.maybeCombine(mx.get(k), y)) - } - } - + with CommutativeMonoid[SortedMap[K, V]] { + private[this] val underlying: CommutativeMonoid[SortedMap[K, V]] = + new cats.kernel.instances.SortedMapCommutativeMonoid[K, V] } +@deprecated("2.0.0-RC2", "Use cats.kernel.instances.SortedMapMonoid") +class SortedMapMonoid[K, V](implicit V: Semigroup[V], O: Order[K]) extends cats.kernel.instances.SortedMapMonoid[K, V] + private[instances] trait SortedMapInstancesBinCompat0 { implicit def catsStdTraverseFilterForSortedMap[K: Order]: TraverseFilter[SortedMap[K, *]] = new TraverseFilter[SortedMap[K, *]] { @@ -231,3 +194,5 @@ private[instances] trait SortedMapInstancesBinCompat1 { override def combineK[A](x: SortedMap[K, A], y: SortedMap[K, A]): SortedMap[K, A] = x ++ y } } + +private[instances] trait SortedMapInstancesBinCompat2 extends cats.kernel.instances.SortedMapInstances diff --git a/core/src/main/scala/cats/instances/sortedSet.scala b/core/src/main/scala/cats/instances/sortedSet.scala index 0855b8d3d6..7f55f58fe3 100644 --- a/core/src/main/scala/cats/instances/sortedSet.scala +++ b/core/src/main/scala/cats/instances/sortedSet.scala @@ -2,10 +2,8 @@ package cats package instances import cats.kernel.{BoundedSemilattice, Hash, Order} -import cats.kernel.instances.StaticMethods import scala.collection.immutable.SortedSet import scala.annotation.tailrec -import cats.implicits._ trait SortedSetInstances extends SortedSetInstances1 { @@ -64,19 +62,22 @@ trait SortedSetInstances extends SortedSetInstances1 { implicit def catsStdShowForSortedSet[A: Show]: Show[SortedSet[A]] = new Show[SortedSet[A]] { def show(fa: SortedSet[A]): String = - fa.iterator.map(_.show).mkString("SortedSet(", ", ", ")") + fa.iterator.map(Show[A].show).mkString("SortedSet(", ", ", ")") } - implicit def catsKernelStdOrderForSortedSet[A: Order]: Order[SortedSet[A]] = - new SortedSetOrder[A] + @deprecated("2.0.0-RC2", "Use cats.kernel.instances.sortedSet.catsKernelStdOrderForSortedSet") + private[instances] def catsKernelStdOrderForSortedSet[A: Order]: Order[SortedSet[A]] = + cats.kernel.instances.sortedSet.catsKernelStdOrderForSortedSet[A] } private[instances] trait SortedSetInstances1 { - implicit def catsKernelStdHashForSortedSet[A: Order: Hash]: Hash[SortedSet[A]] = - new SortedSetHash[A] + @deprecated("2.0.0-RC2", "Use cats.kernel.instances.sortedSet.catsKernelStdHashForSortedSet") + private[instances] def catsKernelStdHashForSortedSet[A: Order: Hash]: Hash[SortedSet[A]] = + cats.kernel.instances.sortedSet.catsKernelStdHashForSortedSet[A] - implicit def catsKernelStdSemilatticeForSortedSet[A: Order]: BoundedSemilattice[SortedSet[A]] = - new SortedSetSemilattice[A] + @deprecated("2.0.0-RC2", "Use cats.kernel.instances.sortedSet.catsKernelStdSemilatticeForSortedSet") + private[instances] def catsKernelStdSemilatticeForSortedSet[A: Order]: BoundedSemilattice[SortedSet[A]] = + cats.kernel.instances.sortedSet.catsKernelStdBoundedSemilatticeForSortedSet[A] } private[instances] trait SortedSetInstancesBinCompat0 { @@ -90,43 +91,27 @@ private[instances] trait SortedSetInstancesBinCompat0 { } } -class SortedSetOrder[A: Order] extends Order[SortedSet[A]] { - def compare(a1: SortedSet[A], a2: SortedSet[A]): Int = - Order[Int].compare(a1.size, a2.size) match { - case 0 => StaticMethods.iteratorCompare(a1.iterator, a2.iterator) - case x => x - } - - override def eqv(s1: SortedSet[A], s2: SortedSet[A]): Boolean = - StaticMethods.iteratorEq(s1.iterator, s2.iterator) +private[instances] trait SortedSetInstancesBinCompat1 extends LowPrioritySortedSetInstancesBinCompat1 { + // TODO: Remove when this is no longer necessary for binary compatibility. + implicit override def catsKernelStdHashForSortedSet[A: Order: Hash]: Hash[SortedSet[A]] = + cats.kernel.instances.sortedSet.catsKernelStdHashForSortedSet[A] } -class SortedSetHash[A: Order: Hash] extends Hash[SortedSet[A]] { - import scala.util.hashing.MurmurHash3._ - - // adapted from [[scala.util.hashing.MurmurHash3]], - // but modified standard `Any#hashCode` to `ev.hash`. - def hash(xs: SortedSet[A]): Int = { - var a, b, n = 0 - var c = 1 - xs.foreach { x => - val h = Hash[A].hash(x) - a += h - b ^= h - c = cats.kernel.instances.StaticMethods.updateUnorderedHashC(c, h) - n += 1 - } - var h = setSeed - h = mix(h, a) - h = mix(h, b) - h = mixLast(h, c) - finalizeHash(h, n) - } - override def eqv(s1: SortedSet[A], s2: SortedSet[A]): Boolean = - StaticMethods.iteratorEq(s1.iterator, s2.iterator)(Order[A]) -} +private[instances] trait LowPrioritySortedSetInstancesBinCompat1 + extends cats.kernel.instances.SortedSetInstances + with SortedSetInstances { + implicit override def catsKernelStdOrderForSortedSet[A: Order]: Order[SortedSet[A]] = + cats.kernel.instances.sortedSet.catsKernelStdOrderForSortedSet[A] -class SortedSetSemilattice[A: Order] extends BoundedSemilattice[SortedSet[A]] { - def empty: SortedSet[A] = SortedSet.empty(implicitly[Order[A]].toOrdering) - def combine(x: SortedSet[A], y: SortedSet[A]): SortedSet[A] = x | y + override def catsKernelStdHashForSortedSet[A: Order: Hash]: Hash[SortedSet[A]] = + cats.kernel.instances.sortedSet.catsKernelStdHashForSortedSet[A] } + +@deprecated("2.0.0-RC2", "Use cats.kernel.instances.SortedSetHash") +class SortedSetHash[A: Order: Hash] extends cats.kernel.instances.SortedSetHash[A] + +@deprecated("2.0.0-RC2", "Use cats.kernel.instances.SortedSetOrder") +class SortedSetOrder[A: Order] extends cats.kernel.instances.SortedSetOrder[A] + +@deprecated("2.0.0-RC2", "Use cats.kernel.instances.SortedSetSemilattice") +class SortedSetSemilattice[A: Order] extends cats.kernel.instances.SortedSetSemilattice[A] diff --git a/kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala b/kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala index 59d0bc2c81..f12376e63f 100644 --- a/kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala +++ b/kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala @@ -12,7 +12,7 @@ import org.scalactic.anyvals.{PosInt, PosZInt} import org.scalatest.funsuite.AnyFunSuiteLike import scala.concurrent.duration.{Duration, FiniteDuration} -import scala.collection.immutable.{BitSet, Queue} +import scala.collection.immutable.{BitSet, Queue, SortedMap, SortedSet} import scala.util.Random import java.util.UUID import java.util.concurrent.TimeUnit.{DAYS, HOURS, MICROSECONDS, MILLISECONDS, MINUTES, NANOSECONDS, SECONDS} @@ -64,6 +64,28 @@ object KernelCheck { ) } + // Copied from cats-laws. + implicit def arbitrarySortedMap[K: Arbitrary: Order, V: Arbitrary]: Arbitrary[SortedMap[K, V]] = + Arbitrary(arbitrary[Map[K, V]].map(s => SortedMap.empty[K, V](implicitly[Order[K]].toOrdering) ++ s)) + + // Copied from cats-laws. + implicit def cogenSortedMap[K: Order: Cogen, V: Cogen]: Cogen[SortedMap[K, V]] = { + implicit val orderingK = Order[K].toOrdering + + implicitly[Cogen[Map[K, V]]].contramap(_.toMap) + } + + // Copied from cats-laws. + implicit def arbitrarySortedSet[A: Arbitrary: Order]: Arbitrary[SortedSet[A]] = + Arbitrary(arbitrary[Set[A]].map(s => SortedSet.empty[A](implicitly[Order[A]].toOrdering) ++ s)) + + // Copied from cats-laws. + implicit def cogenSortedSet[A: Order: Cogen]: Cogen[SortedSet[A]] = { + implicit val orderingA = Order[A].toOrdering + + implicitly[Cogen[Set[A]]].contramap(_.toSet) + } + // this instance is not available in ScalaCheck 1.13.2. // remove this once a newer version is available. implicit val cogenBigInt: Cogen[BigInt] = @@ -127,6 +149,7 @@ class Tests extends AnyFunSuiteLike with Discipline with ScalaVersionSpecificTes // needed for Cogen[Map[...]] implicit val ohe: Ordering[HasEq[Int]] = Ordering.by[HasEq[Int], Int](_.a) checkAll("Eq[Map[String, HasEq[Int]]]", EqTests[Map[String, HasEq[Int]]].eqv) + checkAll("Eq[SortedMap[String, HasEq[Int]]]", EqTests[SortedMap[String, HasEq[Int]]].eqv) } checkAll("Eq[List[HasEq[Int]]]", EqTests[List[HasEq[Int]]].eqv) @@ -172,6 +195,7 @@ class Tests extends AnyFunSuiteLike with Discipline with ScalaVersionSpecificTes checkAll("Order[Vector[Int]]", OrderTests[Vector[Int]].order) checkAll("Order[Stream[Int]]", OrderTests[Stream[Int]].order) checkAll("Order[Queue[Int]]", OrderTests[Queue[Int]].order) + checkAll("Order[SortedSet[String]", OrderTests[SortedSet[String]].order) checkAll("fromOrdering[Int]", OrderTests(Order.fromOrdering[Int]).order) checkAll("Order.reverse(Order[Int])", OrderTests(Order.reverse(Order[Int])).order) checkAll("Order.reverse(Order.reverse(Order[Int]))", OrderTests(Order.reverse(Order.reverse(Order[Int]))).order) @@ -217,16 +241,24 @@ class Tests extends AnyFunSuiteLike with Discipline with ScalaVersionSpecificTes checkAll("Monoid[List[String]]", SerializableTests.serializable(Monoid[List[String]])) checkAll("Monoid[Map[String, String]]", MonoidTests[Map[String, String]].monoid) checkAll("Monoid[Map[String, String]]", SerializableTests.serializable(Monoid[Map[String, String]])) + checkAll("Monoid[SortedMap[String, String]]", MonoidTests[SortedMap[String, String]].monoid) + checkAll("Monoid[SortedMap[String, String]]", SerializableTests.serializable(Monoid[SortedMap[String, String]])) checkAll("Monoid[Queue[Int]]", MonoidTests[Queue[Int]].monoid) checkAll("Monoid[Queue[Int]]", SerializableTests.serializable(Monoid[Queue[Int]])) checkAll("CommutativeMonoid[Map[String, Int]]", CommutativeMonoidTests[Map[String, Int]].commutativeMonoid) checkAll("CommutativeMonoid[Map[String, Int]]", SerializableTests.serializable(CommutativeMonoid[Map[String, Int]])) + checkAll("CommutativeMonoid[SortedMap[String, Int]]", + CommutativeMonoidTests[SortedMap[String, Int]].commutativeMonoid) + checkAll("CommutativeMonoid[SortedMap[String, Int]]", + SerializableTests.serializable(CommutativeMonoid[SortedMap[String, Int]])) checkAll("BoundedSemilattice[BitSet]", BoundedSemilatticeTests[BitSet].boundedSemilattice) checkAll("BoundedSemilattice[BitSet]", SerializableTests.serializable(BoundedSemilattice[BitSet])) checkAll("BoundedSemilattice[Set[Int]]", BoundedSemilatticeTests[Set[Int]].boundedSemilattice) checkAll("BoundedSemilattice[Set[Int]]", SerializableTests.serializable(BoundedSemilattice[Set[Int]])) + checkAll("BoundedSemilattice[SortedSet[Int]]", BoundedSemilatticeTests[SortedSet[Int]].boundedSemilattice) + checkAll("BoundedSemilattice[SortedSet[Int]]", SerializableTests.serializable(BoundedSemilattice[SortedSet[Int]])) checkAll("CommutativeGroup[Unit]", CommutativeGroupTests[Unit].commutativeGroup) checkAll("CommutativeGroup[Unit]", SerializableTests.serializable(CommutativeGroup[Unit])) @@ -275,6 +307,7 @@ class Tests extends AnyFunSuiteLike with Discipline with ScalaVersionSpecificTes 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[SortedMap[Int, String]]", HashTests[SortedMap[Int, String]].hash) checkAll("Hash[Queue[Int]", HashTests[Queue[Int]].hash) { diff --git a/kernel/src/main/scala-2.12-/cats/kernel/instances/AllInstances.scala b/kernel/src/main/scala-2.12-/cats/kernel/instances/AllInstances.scala index bcbfe3addd..92cae9dd78 100644 --- a/kernel/src/main/scala-2.12-/cats/kernel/instances/AllInstances.scala +++ b/kernel/src/main/scala-2.12-/cats/kernel/instances/AllInstances.scala @@ -34,3 +34,5 @@ trait AllInstances with VectorInstances private[instances] trait AllInstancesBinCompat0 extends FiniteDurationInstances + +private[instances] trait AllInstancesBinCompat1 extends SortedMapInstances with SortedSetInstances diff --git a/kernel/src/main/scala-2.13+/cats/kernel/instances/AllInstances.scala b/kernel/src/main/scala-2.13+/cats/kernel/instances/AllInstances.scala index 66bd5d7b27..90407bb0f6 100644 --- a/kernel/src/main/scala-2.13+/cats/kernel/instances/AllInstances.scala +++ b/kernel/src/main/scala-2.13+/cats/kernel/instances/AllInstances.scala @@ -35,3 +35,5 @@ trait AllInstances with VectorInstances private[instances] trait AllInstancesBinCompat0 extends FiniteDurationInstances + +private[instances] trait AllInstancesBinCompat1 extends SortedMapInstances with SortedSetInstances diff --git a/kernel/src/main/scala/cats/kernel/instances/SortedMapInstances.scala b/kernel/src/main/scala/cats/kernel/instances/SortedMapInstances.scala new file mode 100644 index 0000000000..337fe59a45 --- /dev/null +++ b/kernel/src/main/scala/cats/kernel/instances/SortedMapInstances.scala @@ -0,0 +1,84 @@ +package cats.kernel +package instances + +import scala.collection.immutable.SortedMap + +trait SortedMapInstances extends SortedMapInstances2 { + implicit def catsKernelStdHashForSortedMap[K: Hash: Order, V: Hash]: Hash[SortedMap[K, V]] = + new SortedMapHash[K, V] + + implicit def catsKernelStdCommutativeMonoidForSortedMap[K: Order, V: CommutativeSemigroup] + : CommutativeMonoid[SortedMap[K, V]] = + new SortedMapCommutativeMonoid[K, V] +} + +private[instances] trait SortedMapInstances1 { + implicit def catsKernelStdEqForSortedMap[K: Order, V: Eq]: Eq[SortedMap[K, V]] = + new SortedMapEq[K, V] +} + +private[instances] trait SortedMapInstances2 extends SortedMapInstances1 { + implicit def catsKernelStdMonoidForSortedMap[K: Order, V: Semigroup]: Monoid[SortedMap[K, V]] = + new SortedMapMonoid[K, V] +} + +class SortedMapHash[K, V](implicit V: Hash[V], O: Order[K], K: Hash[K]) + extends SortedMapEq[K, V]()(V, O) + with Hash[SortedMap[K, V]] { + // adapted from [[scala.util.hashing.MurmurHash3]], + // but modified standard `Any#hashCode` to `ev.hash`. + import scala.util.hashing.MurmurHash3._ + def hash(x: SortedMap[K, V]): Int = { + var a, b, n = 0 + var c = 1 + x.foreach { + case (k, v) => + val h = StaticMethods.product2HashWithPrefix(K.hash(k), V.hash(v), "Tuple2") + a += h + b ^= h + c = StaticMethods.updateUnorderedHashC(c, h) + n += 1 + } + var h = mapSeed + h = mix(h, a) + h = mix(h, b) + h = mixLast(h, c) + finalizeHash(h, n) + } +} + +class SortedMapEq[K, V](implicit V: Eq[V], O: Order[K]) extends Eq[SortedMap[K, V]] { + def eqv(x: SortedMap[K, V], y: SortedMap[K, V]): Boolean = + if (x eq y) true + else + x.size == y.size && x.forall { + case (k, v1) => + y.get(k) match { + case Some(v2) => V.eqv(v1, v2) + case None => false + } + } +} + +class SortedMapCommutativeMonoid[K, V](implicit V: CommutativeSemigroup[V], O: Order[K]) + extends SortedMapMonoid[K, V] + with CommutativeMonoid[SortedMap[K, V]] + +class SortedMapMonoid[K, V](implicit V: Semigroup[V], O: Order[K]) extends Monoid[SortedMap[K, V]] { + + def empty: SortedMap[K, V] = SortedMap.empty(O.toOrdering) + + def combine(xs: SortedMap[K, V], ys: SortedMap[K, V]): SortedMap[K, V] = + if (xs.size <= ys.size) { + xs.foldLeft(ys) { + case (my, (k, x)) => + my.updated(k, Semigroup.maybeCombine(x, my.get(k))) + } + } else { + ys.foldLeft(xs) { + case (mx, (k, y)) => + mx.updated(k, Semigroup.maybeCombine(mx.get(k), y)) + } + } + +} diff --git a/kernel/src/main/scala/cats/kernel/instances/SortedSetInstances.scala b/kernel/src/main/scala/cats/kernel/instances/SortedSetInstances.scala new file mode 100644 index 0000000000..618c6610d1 --- /dev/null +++ b/kernel/src/main/scala/cats/kernel/instances/SortedSetInstances.scala @@ -0,0 +1,59 @@ +package cats.kernel +package instances + +import cats.kernel.{BoundedSemilattice, Hash, Order} +import scala.collection.immutable.SortedSet + +trait SortedSetInstances extends SortedSetInstances1 { + implicit def catsKernelStdHashForSortedSet[A: Order: Hash]: Hash[SortedSet[A]] = + new SortedSetHash[A] +} + +private[instances] trait SortedSetInstances1 { + implicit def catsKernelStdOrderForSortedSet[A: Order]: Order[SortedSet[A]] = + new SortedSetOrder[A] + + implicit def catsKernelStdBoundedSemilatticeForSortedSet[A: Order]: BoundedSemilattice[SortedSet[A]] = + new SortedSetSemilattice[A] +} + +class SortedSetOrder[A: Order] extends Order[SortedSet[A]] { + def compare(a1: SortedSet[A], a2: SortedSet[A]): Int = + cats.kernel.instances.int.catsKernelStdOrderForInt.compare(a1.size, a2.size) match { + case 0 => StaticMethods.iteratorCompare(a1.iterator, a2.iterator) + case x => x + } + + override def eqv(s1: SortedSet[A], s2: SortedSet[A]): Boolean = + StaticMethods.iteratorEq(s1.iterator, s2.iterator) +} + +class SortedSetHash[A: Order: Hash] extends Hash[SortedSet[A]] { + import scala.util.hashing.MurmurHash3._ + + // adapted from [[scala.util.hashing.MurmurHash3]], + // but modified standard `Any#hashCode` to `ev.hash`. + def hash(xs: SortedSet[A]): Int = { + var a, b, n = 0 + var c = 1 + xs.foreach { x => + val h = Hash[A].hash(x) + a += h + b ^= h + c = cats.kernel.instances.StaticMethods.updateUnorderedHashC(c, h) + n += 1 + } + var h = setSeed + h = mix(h, a) + h = mix(h, b) + h = mixLast(h, c) + finalizeHash(h, n) + } + override def eqv(s1: SortedSet[A], s2: SortedSet[A]): Boolean = + StaticMethods.iteratorEq(s1.iterator, s2.iterator)(Order[A]) +} + +class SortedSetSemilattice[A: Order] extends BoundedSemilattice[SortedSet[A]] { + def empty: SortedSet[A] = SortedSet.empty(implicitly[Order[A]].toOrdering) + def combine(x: SortedSet[A], y: SortedSet[A]): SortedSet[A] = x | y +} diff --git a/kernel/src/main/scala/cats/kernel/instances/all/package.scala b/kernel/src/main/scala/cats/kernel/instances/all/package.scala index f6caf91d77..510c2b320f 100644 --- a/kernel/src/main/scala/cats/kernel/instances/all/package.scala +++ b/kernel/src/main/scala/cats/kernel/instances/all/package.scala @@ -1,4 +1,4 @@ package cats.kernel package instances -package object all extends AllInstances with AllInstancesBinCompat0 +package object all extends AllInstances with AllInstancesBinCompat0 with AllInstancesBinCompat1 diff --git a/kernel/src/main/scala/cats/kernel/instances/sortedMap/package.scala b/kernel/src/main/scala/cats/kernel/instances/sortedMap/package.scala new file mode 100644 index 0000000000..737eef88db --- /dev/null +++ b/kernel/src/main/scala/cats/kernel/instances/sortedMap/package.scala @@ -0,0 +1,4 @@ +package cats.kernel +package instances + +package object sortedMap extends SortedMapInstances diff --git a/kernel/src/main/scala/cats/kernel/instances/sortedSet/package.scala b/kernel/src/main/scala/cats/kernel/instances/sortedSet/package.scala new file mode 100644 index 0000000000..edddfb1011 --- /dev/null +++ b/kernel/src/main/scala/cats/kernel/instances/sortedSet/package.scala @@ -0,0 +1,4 @@ +package cats.kernel +package instances + +package object sortedSet extends SortedSetInstances diff --git a/tests/src/test/scala/cats/tests/CatsSuite.scala b/tests/src/test/scala/cats/tests/CatsSuite.scala index d9b2f67db7..d98191ba7f 100644 --- a/tests/src/test/scala/cats/tests/CatsSuite.scala +++ b/tests/src/test/scala/cats/tests/CatsSuite.scala @@ -44,6 +44,7 @@ trait CatsSuite with AllInstancesBinCompat3 with AllInstancesBinCompat4 with AllInstancesBinCompat5 + with AllInstancesBinCompat6 with AllSyntax with AllSyntaxBinCompat0 with AllSyntaxBinCompat1