Skip to content
1 change: 0 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ ThisBuild / startYear := Some(2015)

ThisBuild / crossScalaVersions := Seq(Scala3, Scala213, Scala212)
ThisBuild / tlVersionIntroduced := Map("3" -> "0.9.3")
ThisBuild / tlFatalWarnings := false
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

ThisBuild / tlCiReleaseBranches := Seq("master")
ThisBuild / tlSitePublishBranch := Some("master")
ThisBuild / githubWorkflowJavaVersions := Seq("8", "21").map(JavaSpec.temurin)
Expand Down
32 changes: 18 additions & 14 deletions core/src/main/scala/cats/collections/Dequeue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import cats.data.NonEmptyList
import scala.annotation.tailrec
import scala.collection.mutable.ListBuffer
import cats.collections.compat.Factory
import org.typelevel.scalaccompat.annotation._

/**
* Dequeue - A Double Ended Queue
Expand Down Expand Up @@ -324,25 +325,28 @@ sealed trait DequeueInstances {
override def combine(l: Dequeue[A], r: Dequeue[A]) = l ++ r
}

implicit val dequeueInstance: Traverse[Dequeue] with MonoidK[Dequeue] with CoflatMap[Dequeue] = new Traverse[Dequeue]
with MonoidK[Dequeue]
with CoflatMap[Dequeue] {
override def empty[A]: Dequeue[A] = Dequeue.empty
@nowarn213(
"msg=Calls to parameterless method compose will be easy to mistake for calls to overloads which have a single implicit parameter list"
)
implicit val dequeueInstance: Traverse[Dequeue] with MonoidK[Dequeue] with CoflatMap[Dequeue] =
new Traverse[Dequeue] with MonoidK[Dequeue] with CoflatMap[Dequeue] {
override def empty[A]: Dequeue[A] = Dequeue.empty

override def combineK[A](l: Dequeue[A], r: Dequeue[A]): Dequeue[A] = l ++ r
override def combineK[A](l: Dequeue[A], r: Dequeue[A]): Dequeue[A] = l ++ r

override def map[A, B](fa: Dequeue[A])(f: A => B) = fa.map(f)
override def map[A, B](fa: Dequeue[A])(f: A => B) = fa.map(f)

override def coflatMap[A, B](fa: Dequeue[A])(f: Dequeue[A] => B): Dequeue[B] = fa.coflatMap(f)
override def coflatMap[A, B](fa: Dequeue[A])(f: Dequeue[A] => B): Dequeue[B] = fa.coflatMap(f)

override def foldLeft[A, B](fa: Dequeue[A], b: B)(f: (B, A) => B): B =
fa.foldLeft(b)(f)
override def foldLeft[A, B](fa: Dequeue[A], b: B)(f: (B, A) => B): B =
fa.foldLeft(b)(f)

override def foldRight[A, B](fa: Dequeue[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = fa.foldRight(lb)(f)
override def foldRight[A, B](fa: Dequeue[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
fa.foldRight(lb)(f)

override def traverse[G[_], A, B](fa: Dequeue[A])(f: A => G[B])(implicit G: Applicative[G]): G[Dequeue[B]] = {
val gba = G.pure(EmptyDequeue[B]())
fa.foldLeft(gba)((bs, a) => G.map2(bs, f(a))(_ :+ _))
override def traverse[G[_], A, B](fa: Dequeue[A])(f: A => G[B])(implicit G: Applicative[G]): G[Dequeue[B]] = {
val gba = G.pure(EmptyDequeue[B]())
fa.foldLeft(gba)((bs, a) => G.map2(bs, f(a))(_ :+ _))
}
}
}
}
44 changes: 24 additions & 20 deletions core/src/main/scala/cats/collections/HashMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ import cats.kernel.Monoid
import cats.kernel.compat.scalaVersionSpecific._
import cats.syntax.eq._

import org.typelevel.scalaccompat.annotation.unused

import java.util.Arrays

import HashMap.improve
Expand Down Expand Up @@ -216,12 +218,12 @@ final class HashMap[K, +V] private[collections] (private[collections] val rootNo
/**
* Typesafe equality operator.
*
* This method is similar to [[scala.Any#==]] except that it only allows two [[cats.data.HashMap]] values of the same
* key-value type to be compared to each other, and uses equality provided by [[cats.kernel.Eq]] instances, rather
* than using the universal equality provided by [[java.lang.Object#equals]].
* This method is similar to [[scala.Any#==]] except that it only allows two [[HashMap]] values of the same key-value
* type to be compared to each other, and uses equality provided by [[cats.kernel.Eq]] instances, rather than using
* the universal equality provided by [[java.lang.Object#equals]].
*
* @param that
* the [[cats.data.HashMap]] to check for equality with this map.
* the [[HashMap]] to check for equality with this map.
* @param eqValue
* the [[cats.kernel.Eq]] instance to use for comparing values.
* @return
Expand Down Expand Up @@ -309,38 +311,38 @@ object HashMap extends HashMapInstances with compat.HashMapCompatCompanion {
scala.util.hashing.byteswap32(hash)

/**
* Creates a new empty [[cats.data.HashMap]] which uses `hashKey` for hashing.
* Creates a new empty [[HashMap]] which uses `hashKey` for hashing.
*
* @param hashKey
* the [[cats.kernel.Hash]] instance used for hashing keys.
* @return
* a new empty [[cats.data.HashMap]].
* a new empty [[HashMap]].
*/
final def empty[K, V](implicit hashKey: Hash[K]): HashMap[K, V] =
new HashMap[K, V](Node.empty[K, V])

/**
* Creates a new [[cats.data.HashMap]] which contains all elements of `kvs`.
* Creates a new [[HashMap]] which contains all elements of `kvs`.
*
* @param kvs
* the key-value pairs to add to the [[cats.data.HashMap]].
* the key-value pairs to add to the [[HashMap]].
* @param hashKey
* the [[cats.kernel.Hash]] instance used for hashing keys.
* @return
* a new [[cats.data.HashMap]] which contains all elements of `kvs`.
* a new [[HashMap]] which contains all elements of `kvs`.
*/
final def apply[K, V](kvs: (K, V)*)(implicit hashKey: Hash[K]) =
fromSeq(kvs)

/**
* Creates a new [[cats.data.HashMap]] which contains all elements of `seq`.
* Creates a new [[HashMap]] which contains all elements of `seq`.
*
* @param seq
* the sequence of elements to add to the [[cats.data.HashMap]].
* the sequence of elements to add to the [[HashMap]].
* @param hashKey
* the [[cats.kernel.Hash]] instance used for hashing values.
* @return
* a new [[cats.data.HashMap]] which contains all elements of `seq`.
* a new [[HashMap]] which contains all elements of `seq`.
*/
final def fromSeq[K, V](seq: Seq[(K, V)])(implicit hashKey: Hash[K]): HashMap[K, V] = {
val rootNode = seq.foldLeft(Node.empty[K, V]) { case (node, (k, v)) =>
Expand All @@ -350,14 +352,14 @@ object HashMap extends HashMapInstances with compat.HashMapCompatCompanion {
}

/**
* Creates a new [[cats.data.HashMap]] which contains all elements of `iterable`.
* Creates a new [[HashMap]] which contains all elements of `iterable`.
*
* @param iterable
* the iterable source of elements to add to the [[cats.data.HashMap]].
* the iterable source of elements to add to the [[HashMap]].
* @param hashKey
* the [[cats.kernel.Hash]] instance used for hashing values.
* @return
* a new [[cats.data.HashMap]] which contains all elements of `iterable`.
* a new [[HashMap]] which contains all elements of `iterable`.
*/
final def fromIterableOnce[K, V](iterable: IterableOnce[(K, V)])(implicit hashKey: Hash[K]): HashMap[K, V] = {
iterable match {
Expand All @@ -372,16 +374,16 @@ object HashMap extends HashMapInstances with compat.HashMapCompatCompanion {
}

/**
* Creates a new [[cats.data.HashMap]] which contains all elements of `fkv`.
* Creates a new [[HashMap]] which contains all elements of `fkv`.
*
* @param fkv
* the [[cats.Foldable]] structure of elements to add to the [[cats.data.HashMap]].
* the [[cats.Foldable]] structure of elements to add to the [[HashMap]].
* @param F
* the [[cats.Foldable]] instance used for folding the structure.
* @param hashKey
* the [[cats.kernel.Hash]] instance used for hashing values.
* @return
* a new [[cats.data.HashMap]] which contains all elements of `fkv`.
* a new [[HashMap]] which contains all elements of `fkv`.
*/
final def fromFoldable[F[_], K, V](fkv: F[(K, V)])(implicit F: Foldable[F], hashKey: Hash[K]): HashMap[K, V] = {
val rootNode = F.foldLeft(fkv, Node.empty[K, V]) { case (node, (k, v)) =>
Expand Down Expand Up @@ -527,7 +529,7 @@ object HashMap extends HashMapInstances with compat.HashMapCompatCompanion {
* rather than using the universal equality provided by [[java.lang.Object#equals]].
*
* @param that
* the [[cats.data.HashMap.Node]] to check for equality with this node.
* the [[HashMap.Node]] to check for equality with this node.
* @param eqValue
* the [[cats.kernel.Eq]] instance to use for comparing values.
* @return
Expand Down Expand Up @@ -1427,7 +1429,9 @@ object HashMap extends HashMapInstances with compat.HashMapCompatCompanion {
}

sealed abstract private[collections] class HashMapInstances extends HashMapInstances1 {
implicit def catsCollectionsUnorderedTraverseForHashMap[K: Hash]: UnorderedTraverse[HashMap[K, *]] =
implicit def catsCollectionsUnorderedTraverseForHashMap[K](implicit
@unused ev: Hash[K]
): UnorderedTraverse[HashMap[K, *]] =
new UnorderedTraverse[HashMap[K, *]] {
override def nonEmpty[A](fa: HashMap[K, A]): Boolean = fa.nonEmpty

Expand Down
36 changes: 18 additions & 18 deletions core/src/main/scala/cats/collections/HashSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -273,12 +273,12 @@ final class HashSet[A] private (private val rootNode: HashSet.Node[A])(implicit
/**
* Typesafe equality operator.
*
* This method is similar to [[scala.Any#==]] except that it only allows two [[cats.data.HashSet]] values of the same
* element type to be compared to each other, and uses equality provided by [[cats.kernel.Eq]] instances, rather than
* using the universal equality provided by [[java.lang.Object#equals]].
* This method is similar to [[scala.Any#==]] except that it only allows two [[HashSet]] values of the same element
* type to be compared to each other, and uses equality provided by [[cats.kernel.Eq]] instances, rather than using
* the universal equality provided by [[java.lang.Object#equals]].
*
* @param that
* the [[cats.data.HashSet]] to check for equality with this set.
* the [[HashSet]] to check for equality with this set.
* @return
* `true` if this set and `that` are equal, `false` otherwise.
*/
Expand Down Expand Up @@ -319,38 +319,38 @@ object HashSet extends compat.HashSetCompatCompanion {
scala.util.hashing.byteswap32(hash)

/**
* Creates a new empty [[cats.data.HashSet]] which uses `hash` for hashing.
* Creates a new empty [[HashSet]] which uses `hash` for hashing.
*
* @param hash
* the [[cats.kernel.Hash]] instance used for hashing values.
* @return
* a new empty [[cats.data.HashSet]].
* a new empty [[HashSet]].
*/
final def empty[A](implicit hash: Hash[A]): HashSet[A] =
new HashSet(Node.empty[A])

/**
* Creates a new [[cats.data.HashSet]] which contains all elements of `as`.
* Creates a new [[HashSet]] which contains all elements of `as`.
*
* @param as
* the elements to add to the [[cats.data.HashSet]].
* the elements to add to the [[HashSet]].
* @param hash
* the [[cats.kernel.Hash]] instance used for hashing values.
* @return
* a new [[cats.data.HashSet]] which contains all elements of `as`.
* a new [[HashSet]] which contains all elements of `as`.
*/
final def apply[A](as: A*)(implicit hash: Hash[A]) =
fromSeq(as)

/**
* Creates a new [[cats.data.HashSet]] which contains all elements of `seq`.
* Creates a new [[HashSet]] which contains all elements of `seq`.
*
* @param seq
* the sequence of elements to add to the [[cats.data.HashSet]].
* the sequence of elements to add to the [[HashSet]].
* @param hash
* the [[cats.kernel.Hash]] instance used for hashing values.
* @return
* a new [[cats.data.HashSet]] which contains all elements of `seq`.
* a new [[HashSet]] which contains all elements of `seq`.
*/
final def fromSeq[A](seq: Seq[A])(implicit hash: Hash[A]): HashSet[A] = {
val rootNode = seq.foldLeft(Node.empty[A]) { case (node, a) =>
Expand All @@ -360,14 +360,14 @@ object HashSet extends compat.HashSetCompatCompanion {
}

/**
* Creates a new [[cats.data.HashSet]] which contains all elements of `iterable`.
* Creates a new [[HashSet]] which contains all elements of `iterable`.
*
* @param seq
* the iterable source of elements to add to the [[cats.data.HashSet]].
* the iterable source of elements to add to the [[HashSet]].
* @param hash
* the [[cats.kernel.Hash]] instance used for hashing values.
* @return
* a new [[cats.data.HashSet]] which contains all elements of `iterable`.
* a new [[HashSet]] which contains all elements of `iterable`.
*/
final def fromIterableOnce[A](iterable: IterableOnce[A])(implicit hash: Hash[A]): HashSet[A] = {
iterable match {
Expand All @@ -382,16 +382,16 @@ object HashSet extends compat.HashSetCompatCompanion {
}

/**
* Creates a new [[cats.data.HashSet]] which contains all elements of `fkv`.
* Creates a new [[HashSet]] which contains all elements of `fkv`.
*
* @param fa
* the [[cats.Foldable]] structure of elements to add to the [[cats.data.HashSet]].
* the [[cats.Foldable]] structure of elements to add to the [[HashSet]].
* @param F
* the [[cats.Foldable]] instance used for folding the structure.
* @param hash
* the [[cats.kernel.Hash]] instance used for hashing values.
* @return
* a new [[cats.data.HashSet]] which contains all elements of `fa`.
* a new [[HashSet]] which contains all elements of `fa`.
*/
final def fromFoldable[F[_], A](fa: F[A])(implicit F: Foldable[F], hash: Hash[A]): HashSet[A] = {
val rootNode = F.foldLeft(fa, Node.empty[A]) { case (node, a) =>
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/scala/cats/collections/TreeList.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import cats.{

import cats.implicits._
import scala.annotation.tailrec
import org.typelevel.scalaccompat.annotation._

/**
* Implementation of "Purely Functional Random Access Lists" by Chris Okasaki. This gives O(1) cons and uncons, and 2
Expand Down Expand Up @@ -791,6 +792,9 @@ object TreeList extends TreeListInstances0 {
ts.toIterator.map(sa.show(_)).mkString("TreeList(", ", ", ")")
}

@nowarn213(
"msg=Calls to parameterless method compose will be easy to mistake for calls to overloads which have a single implicit parameter list"
)
implicit val catsCollectionTreeListInstances: Traverse[TreeList]
with Alternative[TreeList]
with Monad[TreeList]
Expand Down
4 changes: 2 additions & 2 deletions tests/src/test/scala/cats/collections/DequeueSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ class DequeueSuite extends DisciplineSuite {
assertEquals(q.toList, Foldable[Dequeue].toList(q))
})

property("toList/toStream consistency")(forAll { (q: Dequeue[Int]) =>
assertEquals(q.toList, q.to[Stream, Int].toList)
property("toList/toVector consistency")(forAll { (q: Dequeue[Int]) =>
assertEquals(q.toList, q.to[Vector, Int].toList)
Comment on lines -133 to +134
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for posterity: this change is reasonable because what was being tested was not specific to Stream (or laziness). This is about testing the factory-based to method.

})

property("equality")(forAll { (xs: List[Int]) =>
Expand Down
4 changes: 2 additions & 2 deletions tests/src/test/scala/cats/collections/DisjointSetsSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ class DisjointSetsSuite extends FunSuite {
dsets.union(v, v % 10)._1
}

val groupByClassification = numbers.groupBy(_ % 10).mapValues(_.toSet).toMap
val groupByClassification = numbers.groupBy(_ % 10).transform((_, v) => v.toSet).toMap
val (_, disjointSetsClassification) = classifiedNumbers.toSets

assertEquals(
disjointSetsClassification.toScalaMap.mapValues(_.toScalaSet).toMap,
disjointSetsClassification.toScalaMap.transform((_, v) => v.toScalaSet).toMap,
groupByClassification
)
}
Expand Down
Loading