From 396947e9caecfcf27697c8513b18ac94c97f72a7 Mon Sep 17 00:00:00 2001 From: Pietari Kettunen Date: Wed, 26 Feb 2020 12:01:57 +0100 Subject: [PATCH 1/2] tuple 2 & 3 for lazy zipped implementation --- .../scala/collection/compat/package.scala | 10 ++++++ .../collection/compat/PackageShared.scala | 34 ++++++++++++++++--- .../scala/collection/compat/package.scala | 11 ++++++ .../test/scala/collection/LazyZipTest.scala | 32 +++++++++++++++++ 4 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 compat/src/test/scala/test/scala/collection/LazyZipTest.scala diff --git a/compat/src/main/scala-2.11/scala/collection/compat/package.scala b/compat/src/main/scala-2.11/scala/collection/compat/package.scala index 8cdd3c38..d2a33640 100644 --- a/compat/src/main/scala-2.11/scala/collection/compat/package.scala +++ b/compat/src/main/scala-2.11/scala/collection/compat/package.scala @@ -13,6 +13,7 @@ package scala.collection import scala.collection.generic.{CanBuildFrom, GenericOrderedCompanion, IsTraversableLike} +import scala.runtime.Tuple2Zipped import scala.{collection => c} package object compat extends compat.PackageShared { @@ -39,4 +40,13 @@ package object compat extends compat.PackageShared { implicit def toSeqExtensionMethods[A](self: c.Seq[A]): SeqExtensionMethods[A] = new SeqExtensionMethods[A](self) + + implicit def toTrulyTraversableLikeExtensionMethods[T1, El1, Repr1](self: T1)( + implicit w1: T1 => TraversableLike[El1, Repr1]) + : TrulyTraversableLikeExtensionMethods[T1, El1, Repr1] = + new TrulyTraversableLikeExtensionMethods[T1, El1, Repr1](self) + + implicit def toTuple2ZippedExtensionMethods[El1, Repr1, El2, Repr2](self: Tuple2Zipped[El1, Repr1, El2, Repr2]) + : Tuple2ZippedExtensionMethods[El1, Repr1, El2, Repr2] = + new Tuple2ZippedExtensionMethods[El1, Repr1, El2, Repr2](self) } diff --git a/compat/src/main/scala-2.11_2.12/scala/collection/compat/PackageShared.scala b/compat/src/main/scala-2.11_2.12/scala/collection/compat/PackageShared.scala index 62f6d728..34ec2a2d 100644 --- a/compat/src/main/scala-2.11_2.12/scala/collection/compat/PackageShared.scala +++ b/compat/src/main/scala-2.11_2.12/scala/collection/compat/PackageShared.scala @@ -14,8 +14,17 @@ package scala.collection.compat import scala.collection.generic._ import scala.reflect.ClassTag -import scala.collection.{MapLike, GenTraversable, BitSet, IterableView} -import scala.collection.{immutable => i, mutable => m} +import scala.collection.{ + BitSet, + GenTraversable, + IterableLike, + IterableView, + MapLike, + TraversableLike, + immutable => i, + mutable => m +} +import scala.runtime.{Tuple2Zipped, Tuple3Zipped} import scala.{collection => c} /** The collection compatibility API */ @@ -233,7 +242,7 @@ class IteratorExtensionMethods[A](private val self: c.Iterator[A]) extends AnyVa self.sameElements(that.iterator) } def concat[B >: A](that: c.TraversableOnce[B]): c.TraversableOnce[B] = self ++ that - def tapEach[U](f: A => U): c.Iterator[A] = self.map(a => { f(a); a }) + def tapEach[U](f: A => U): c.Iterator[A] = self.map(a => { f(a); a }) } class TraversableOnceExtensionMethods[A](private val self: c.TraversableOnce[A]) extends AnyVal { @@ -246,6 +255,7 @@ class TraversableExtensionMethods[A](private val self: c.Traversable[A]) extends def sizeCompare(otherSize: Int): Int = SizeCompareImpl.sizeCompareInt(self)(otherSize) def sizeIs: SizeCompareOps = new SizeCompareOps(self) def sizeCompare(that: c.Traversable[_]): Int = SizeCompareImpl.sizeCompareColl(self)(that) + } class SeqExtensionMethods[A](private val self: c.Seq[A]) extends AnyVal { @@ -338,7 +348,7 @@ class TraversableLikeExtensionMethods[A, Repr](private val self: c.GenTraversabl val k = key(elem) val v = map.get(k) match { case Some(b) => reduce(b, f(elem)) - case None => f(elem) + case None => f(elem) } map.put(k, v) } @@ -346,6 +356,22 @@ class TraversableLikeExtensionMethods[A, Repr](private val self: c.GenTraversabl } } +class TrulyTraversableLikeExtensionMethods[T1, El1, Repr1](private val self: T1) extends AnyVal { + def lazyZip[El2, Repr2, T2](t2: T2)( + implicit w: T1 => TraversableLike[El1, Repr1], + w2: T2 => IterableLike[El2, Repr2]): Tuple2Zipped[El1, Repr1, El2, Repr2] = + new Tuple2Zipped((w(self), t2)) + +} + +class Tuple2ZippedExtensionMethods[El1, Repr1, El2, Repr2](private val self: Tuple2Zipped[El1, Repr1, El2, Repr2]) { + def lazyZip[El3, Repr3, T3](t3: T3)(implicit w3: T3 => IterableLike[El3, Repr3]) + : Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3] = { + + new Tuple3Zipped((self.colls._1, self.colls._2, t3)) + } +} + class MapViewExtensionMethods[K, V, C <: scala.collection.Map[K, V]]( private val self: IterableView[(K, V), C]) extends AnyVal { diff --git a/compat/src/main/scala-2.12/scala/collection/compat/package.scala b/compat/src/main/scala-2.12/scala/collection/compat/package.scala index 012532d4..20b26ec7 100644 --- a/compat/src/main/scala-2.12/scala/collection/compat/package.scala +++ b/compat/src/main/scala-2.12/scala/collection/compat/package.scala @@ -15,6 +15,7 @@ package scala.collection import scala.collection.generic.{CanBuildFrom, GenericOrderedCompanion, IsTraversableLike} import scala.{collection => c} import scala.collection.{mutable => m} +import scala.runtime.Tuple2Zipped package object compat extends compat.PackageShared { implicit class MutableTreeMapExtensions2(private val fact: m.TreeMap.type) extends AnyVal { @@ -50,4 +51,14 @@ package object compat extends compat.PackageShared { implicit def toSeqExtensionMethods[A](self: c.Seq[A]): SeqExtensionMethods[A] = new SeqExtensionMethods[A](self) + + implicit def toTrulyTraversableLikeExtensionMethods[T1, El1, Repr1](self: T1)( + implicit w1: T1 => TraversableLike[El1, Repr1]) + : TrulyTraversableLikeExtensionMethods[T1, El1, Repr1] = + new TrulyTraversableLikeExtensionMethods[T1, El1, Repr1](self) + + implicit def toTuple2ZippedExtensionMethods[El1, Repr1, El2, Repr2](self: Tuple2Zipped[El1, Repr1, El2, Repr2]) + : Tuple2ZippedExtensionMethods[El1, Repr1, El2, Repr2] = + new Tuple2ZippedExtensionMethods[El1, Repr1, El2, Repr2](self) } + diff --git a/compat/src/test/scala/test/scala/collection/LazyZipTest.scala b/compat/src/test/scala/test/scala/collection/LazyZipTest.scala new file mode 100644 index 00000000..6d4485e5 --- /dev/null +++ b/compat/src/test/scala/test/scala/collection/LazyZipTest.scala @@ -0,0 +1,32 @@ +package test.scala.collection + +import org.junit.Assert.assertEquals +import org.junit.Test + +import scala.collection.compat._ + +class LazyZipTest { + + private val ws = List(1, 2, 3) + private val xs = List(1, 2, 3, 4, 5, 6) + private val ys = List("a", "b", "c", "d", "e", "f") + private val zs = List(true, false, true, false, true, false) + private val zipped2 = ws lazyZip xs + private val zipped3 = ws lazyZip xs lazyZip ys + private val zipped4 = ws lazyZip xs lazyZip ys lazyZip zs + private val map = Map(1 -> "foo" , 2 -> "bar") + + @Test + def lazyZipTest(): Unit = { + + val res: List[(Int, Int)] = zipped2.map((a, b) => (a, b)) + assertEquals(List((1, 1), (2, 2), (3, 3)), res) + } + + @Test + def lazyZip3_map(): Unit = { + val res: List[(Int, Int, String)] = zipped3.map((a: Int, b: Int, c: String) => (a, b, c)) + + assertEquals(List((1, 1, "a"), (2, 2, "b"), (3, 3, "c")), res) + } +} From 730e6d8b9969ea7e116a7551f13cf95143a08aef Mon Sep 17 00:00:00 2001 From: Pietari Kettunen Date: Wed, 26 Feb 2020 12:35:36 +0100 Subject: [PATCH 2/2] test for lazy evaluation --- .../test/scala/collection/LazyZipTest.scala | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/compat/src/test/scala/test/scala/collection/LazyZipTest.scala b/compat/src/test/scala/test/scala/collection/LazyZipTest.scala index 6d4485e5..60458c47 100644 --- a/compat/src/test/scala/test/scala/collection/LazyZipTest.scala +++ b/compat/src/test/scala/test/scala/collection/LazyZipTest.scala @@ -1,6 +1,8 @@ package test.scala.collection import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Assert.assertFalse import org.junit.Test import scala.collection.compat._ @@ -18,7 +20,6 @@ class LazyZipTest { @Test def lazyZipTest(): Unit = { - val res: List[(Int, Int)] = zipped2.map((a, b) => (a, b)) assertEquals(List((1, 1), (2, 2), (3, 3)), res) } @@ -26,7 +27,19 @@ class LazyZipTest { @Test def lazyZip3_map(): Unit = { val res: List[(Int, Int, String)] = zipped3.map((a: Int, b: Int, c: String) => (a, b, c)) - assertEquals(List((1, 1, "a"), (2, 2, "b"), (3, 3, "c")), res) } + + @Test + def collectionValueIsNotEvaluated(): Unit = { + val st = Stream.cons(1, throw new AssertionError("should not be evaluated")) + ws.lazyZip(st) + } + + @Test + def zip3collectionValueIsNotEvaluated(): Unit = { + val st = Stream.cons(1, throw new AssertionError("should not be evaluated")) + ws.lazyZip(st).lazyZip(st) + } + }