Skip to content

Commit

Permalink
Factor out strict implementations of transformation operations.
Browse files Browse the repository at this point in the history
Add StrictOptimizedMapOps and StrictOptimizedSortedMapOps.

Only operations that were implemented more than once have been factored
out. Some other operations could be factored out so that they could
be reused by custom collection implementations.

Fixes scala/collection-strawman#325
  • Loading branch information
julienrf committed Jun 11, 2018
1 parent c5da7a0 commit 1acaefd
Show file tree
Hide file tree
Showing 18 changed files with 247 additions and 111 deletions.
60 changes: 15 additions & 45 deletions src/library/scala/collection/StrictOptimizedIterableOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import scala.annotation.unchecked.uncheckedVariance
import scala.language.higherKinds

/**
* Trait that overrides operations to take advantage of strict builders.
* Trait that overrides iterable operations to take advantage of strict builders.
*
* @tparam A Elements type
* @tparam CC Collection type constructor
* @tparam C Collection type
*/
trait StrictOptimizedIterableOps[+A, +CC[_], +C]
Expand Down Expand Up @@ -70,54 +71,23 @@ trait StrictOptimizedIterableOps[+A, +CC[_], +C]
// the view-based implementations, but they turn out to be slightly faster because
// a couple of indirection levels are removed

override def map[B](f: A => B): CC[B] = {
val b = iterableFactory.newBuilder[B]
val it = iterator
while (it.hasNext) {
b += f(it.next())
}
b.result()
}
override def map[B](f: A => B): CC[B] =
StrictOptimizedOps.map(iterator, iterableFactory.newBuilder, f)

override def flatMap[B](f: A => IterableOnce[B]): CC[B] = {
val b = iterableFactory.newBuilder[B]
val it = iterator
while (it.hasNext) {
b ++= f(it.next())
}
b.result()
}
override def flatMap[B](f: A => IterableOnce[B]): CC[B] =
StrictOptimizedOps.flatMap(iterator, iterableFactory.newBuilder, f)

override def collect[B](pf: PartialFunction[A, B]): CC[B] = {
val b = iterableFactory.newBuilder[B]
val it = iterator
while (it.hasNext) {
val elem = it.next()
if (pf.isDefinedAt(elem)) {
b += pf.apply(elem)
}
}
b.result()
}
override def concat[B >: A](suffix: Iterable[B]): CC[B] =
StrictOptimizedOps.concat(iterator, suffix.iterator, iterableFactory.newBuilder[B])

override def flatten[B](implicit toIterableOnce: A => IterableOnce[B]): CC[B] = {
val b = iterableFactory.newBuilder[B]
val it = iterator
while (it.hasNext) {
b ++= toIterableOnce(it.next())
}
b.result()
}
override def collect[B](pf: PartialFunction[A, B]): CC[B] =
StrictOptimizedOps.collect(iterator, iterableFactory.newBuilder, pf)

override def zip[B](that: Iterable[B]): CC[(A @uncheckedVariance, B)] = {
val b = iterableFactory.newBuilder[(A, B)]
val it1 = iterator
val it2 = that.iterator
while (it1.hasNext && it2.hasNext) {
b += ((it1.next(), it2.next()))
}
b.result()
}
override def flatten[B](implicit toIterableOnce: A => IterableOnce[B]): CC[B] =
StrictOptimizedOps.flatten(iterator, iterableFactory.newBuilder)

override def zip[B](that: Iterable[B]): CC[(A @uncheckedVariance, B)] =
StrictOptimizedOps.zip(iterator, that.iterator, iterableFactory.newBuilder[(A, B)])

override def zipWithIndex: CC[(A @uncheckedVariance, Int)] = {
val b = iterableFactory.newBuilder[(A, Int)]
Expand Down
29 changes: 29 additions & 0 deletions src/library/scala/collection/StrictOptimizedMapOps.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package scala.collection

import scala.language.higherKinds

/**
* Trait that overrides map operations to take advantage of strict builders.
*
* @tparam K Type of keys
* @tparam V Type of values
* @tparam CC Collection type constructor
* @tparam C Collection type
*/
trait StrictOptimizedMapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C]
extends MapOps[K, V, CC, C]
with StrictOptimizedIterableOps[(K, V), Iterable, C] {

override def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] =
StrictOptimizedOps.map(iterator, mapFactory.newBuilder, f)

override def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): CC[K2, V2] =
StrictOptimizedOps.flatMap(iterator, mapFactory.newBuilder, f)

override def concat[V2 >: V](suffix: Iterable[(K, V2)]): CC[K, V2] =
StrictOptimizedOps.concat(iterator, suffix.iterator, mapFactory.newBuilder)

override def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)]): CC[K2, V2] =
StrictOptimizedOps.collect(iterator, mapFactory.newBuilder, pf)

}
109 changes: 109 additions & 0 deletions src/library/scala/collection/StrictOptimizedOps.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package scala.collection

/**
* Convenient implementations of transformation operations
* based on builders.
*
* All the methods defined here are expected to be called with
* freshly created iterators and builders.
*/
object StrictOptimizedOps {

/**
* @param it Iterator to map elements from
* @param b Builder to use to build the resulting collection
* @param f Element transformation function
* @tparam A Type of elements of the source collection (e.g. `Int`)
* @tparam B Type of elements of the resulting collection (e.g. `String`)
* @tparam C Type of the resulting collection (e.g. `List[String]`)
* @return The resulting collection
*/
@inline def map[A, B, C](it: Iterator[A], b: mutable.Builder[B, C], f: A => B): C = {
while (it.hasNext) {
b += f(it.next())
}
b.result()
}

/**
* @param it Iterator to flatMap elements from
* @param b Builder to use to build the resulting collection
* @param f Element transformation function
* @tparam A Type of elements of the source collection (e.g. `Int`)
* @tparam B Type of elements of the resulting collection (e.g. `String`)
* @tparam C Type of the resulting collection (e.g. `List[String]`)
* @return The resulting collection
*/
@inline def flatMap[A, B, C](it: Iterator[A], b: mutable.Builder[B, C], f: A => IterableOnce[B]): C = {
while (it.hasNext) {
b ++= f(it.next())
}
b.result()
}

/**
* @param it1 Iterator of the first collection
* @param it2 Iterator of the second collection
* @param b Builder to use to build the resulting collection
* @tparam A Type of elements (e.g. `Int`)
* @tparam C Type of the resulting collection (e.g. `List[Int]`)
* @return The resulting collection
*/
@inline def concat[A, C](it1: Iterator[A], it2: Iterator[A], b: mutable.Builder[A, C]): C = {
b ++= it1
b ++= it2
b.result()
}

/**
* @param it Iterator to collect elements from
* @param b Builder to use to build the resulting collection
* @param pf Element transformation partial function
* @tparam A Type of elements of the source collection (e.g. `Int`)
* @tparam B Type of elements of the resulting collection (e.g. `String`)
* @tparam C Type of the resulting collection (e.g. `List[String]`)
* @return The resulting collection
*/
@inline def collect[A, B, C](it: Iterator[A], b: mutable.Builder[B, C], pf: PartialFunction[A, B]): C = {
while (it.hasNext) {
val elem = it.next()
if (pf.isDefinedAt(elem)) {
b += pf.apply(elem)
}
}
b.result()
}

/**
* @param it Iterator to flatten elements from
* @param b Builder to use to build the resulting collection
* @param toIterableOnce Evidence that `A` can be seen as an `IterableOnce[B]`
* @tparam A Type of elements of the source collection (e.g. `List[Int]`)
* @tparam B Type of elements of the resulting collection (e.g. `Int`)
* @tparam C Type of the resulting collection (e.g. `List[Int]`)
* @return The resulting collection
*/
@inline def flatten[A, B, C](it: Iterator[A], b: mutable.Builder[B, C])(implicit toIterableOnce: A => IterableOnce[B]): C = {
while (it.hasNext) {
b ++= toIterableOnce(it.next())
}
b.result()
}

/**
* @param it1 Iterator of the first collection
* @param it2 Iterator of the second collection
* @param b Builder to use to build the resulting collection
* @tparam A Type of elements of the first collection (e.g. `Int`)
* @tparam B Type of elements of the second collection (e.g. `String`)
* @tparam C Type of the resulting collection (e.g. `List[(Int, String)]`)
* @return The resulting collection
*/
@inline def zip[A, B, C](it1: Iterator[A], it2: Iterator[B], b: mutable.Builder[(A, B), C]): C = {
while (it1.hasNext && it2.hasNext) {
b += ((it1.next(), it2.next()))
}
b.result()
}

}
12 changes: 4 additions & 8 deletions src/library/scala/collection/StrictOptimizedSeqOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import scala.language.higherKinds
*/
trait StrictOptimizedSeqOps [+A, +CC[_], +C]
extends Any
with SeqOps[A, CC, C]
with StrictOptimizedIterableOps[A, CC, C] {
with StrictOptimizedIterableOps[A, CC, C]
with SeqOps[A, CC, C] {

override def distinctBy[B](f: A => B): C = {
val builder = newSpecificBuilder
Expand Down Expand Up @@ -45,12 +45,8 @@ trait StrictOptimizedSeqOps [+A, +CC[_], +C]
b.result()
}

override def appendedAll[B >: A](suffix: Iterable[B]): CC[B] = {
val b = iterableFactory.newBuilder[B]
b ++= this
b ++= suffix
b.result()
}
override def appendedAll[B >: A](suffix: Iterable[B]): CC[B] =
StrictOptimizedOps.concat(iterator, suffix.iterator, iterableFactory.newBuilder)

override def prependedAll[B >: A](prefix: Iterable[B]): CC[B] = {
val b = iterableFactory.newBuilder[B]
Expand Down
17 changes: 17 additions & 0 deletions src/library/scala/collection/StrictOptimizedSetOps.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package scala.collection

/**
* Trait that overrides set operations to take advantage of strict builders.
*
* @tparam A Elements type
* @tparam CC Collection type constructor
* @tparam C Collection type
*/
trait StrictOptimizedSetOps[A, +CC[_], +C <: SetOps[A, CC, C]]
extends SetOps[A, CC, C]
with StrictOptimizedIterableOps[A, CC, C] {

override def concat(that: Iterable[A]): C =
StrictOptimizedOps.concat(iterator, that.iterator, newSpecificBuilder)

}
27 changes: 27 additions & 0 deletions src/library/scala/collection/StrictOptimizedSortedMapOps.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package scala.collection

/**
* Trait that overrides sorted map operations to take advantage of strict builders.
*
* @tparam K Type of keys
* @tparam V Type of values
* @tparam CC Collection type constructor
* @tparam C Collection type
*/
trait StrictOptimizedSortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _], +C <: SortedMapOps[K, V, CC, C]]
extends SortedMapOps[K, V, CC, C]
with StrictOptimizedMapOps[K, V, Map, C] {

override def map[K2, V2](f: ((K, V)) => (K2, V2))(implicit ordering: Ordering[K2]): CC[K2, V2] =
StrictOptimizedOps.map(iterator, sortedMapFactory.newBuilder, f)

override def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] =
StrictOptimizedOps.flatMap(iterator, sortedMapFactory.newBuilder, f)

override def concat[V2 >: V](xs: Iterable[(K, V2)]): CC[K, V2] =
StrictOptimizedOps.concat(iterator, xs.iterator, sortedMapFactory.newBuilder)

override def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] =
StrictOptimizedOps.collect(iterator, sortedMapFactory.newBuilder, pf)

}
61 changes: 20 additions & 41 deletions src/library/scala/collection/StrictOptimizedSortedSetOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,27 @@ package collection
import scala.annotation.unchecked.uncheckedVariance
import scala.language.higherKinds

/**
* Trait that overrides sorted set operations to take advantage of strict builders.
*
* @tparam A Elements type
* @tparam CC Collection type constructor
* @tparam C Collection type
*/
trait StrictOptimizedSortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]]
extends SortedSetOps[A, CC, C]
with StrictOptimizedIterableOps[A, Set, C] {

override def map[B : Ordering](f: A => B): CC[B] = {
val b = sortedIterableFactory.newBuilder[B]
val it = iterator
while (it.hasNext) {
b += f(it.next())
}
b.result()
}

override def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] = {
val b = sortedIterableFactory.newBuilder[B]
val it = iterator
while (it.hasNext) {
b ++= f(it.next())
}
b.result()
}

override def zip[B](that: Iterable[B])(implicit ev: Ordering[(A @uncheckedVariance, B)]): CC[(A @uncheckedVariance, B)] = { // sound bcs of VarianceNot
val b = sortedIterableFactory.newBuilder[(A, B)]
val it1 = iterator
val it2 = that.iterator
while (it1.hasNext && it2.hasNext) {
b += ((it1.next(), it2.next()))
}
b.result()
}

override def collect[B : Ordering](pf: PartialFunction[A, B]): CC[B] = {
val b = sortedIterableFactory.newBuilder[B]
val it = iterator
while (it.hasNext) {
val elem = it.next()
if (pf.isDefinedAt(elem)) {
b += pf.apply(elem)
}
}
b.result()
}
with StrictOptimizedSetOps[A, Set, C] {

override def map[B : Ordering](f: A => B): CC[B] =
StrictOptimizedOps.map(iterator, sortedIterableFactory.newBuilder, f)

override def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] =
StrictOptimizedOps.flatMap(iterator, sortedIterableFactory.newBuilder, f)

override def zip[B](that: Iterable[B])(implicit ev: Ordering[(A @uncheckedVariance, B)]): CC[(A @uncheckedVariance, B)] =
StrictOptimizedOps.zip(iterator, that.iterator, sortedIterableFactory.newBuilder[(A, B)])

override def collect[B : Ordering](pf: PartialFunction[A, B]): CC[B] =
StrictOptimizedOps.collect(iterator, sortedIterableFactory.newBuilder, pf)

}
3 changes: 2 additions & 1 deletion src/library/scala/collection/immutable/BitSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ sealed abstract class BitSet
with collection.BitSet
with SortedSetOps[Int, SortedSet, BitSet]
with collection.BitSetOps[BitSet]
with StrictOptimizedIterableOps[Int, Set, BitSet] {
with StrictOptimizedIterableOps[Int, Set, BitSet]
with StrictOptimizedSortedSetOps[Int, SortedSet, BitSet] {

def bitSetFactory = BitSet

Expand Down
5 changes: 3 additions & 2 deletions src/library/scala/collection/immutable/ChampHashMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package collection.immutable

import java.io.{ObjectInputStream, ObjectOutputStream}

import collection.{IterableFactory, Iterator, MapFactory, StrictOptimizedIterableOps}
import collection.{IterableFactory, Iterator, MapFactory, StrictOptimizedIterableOps, StrictOptimizedMapOps}
import collection.Hashing.{computeHash, keepBits}
import scala.annotation.unchecked.{uncheckedVariance => uV}
import java.lang.Integer.bitCount
Expand All @@ -26,7 +26,8 @@ import scala.collection.mutable.{Builder, ImmutableBuilder}
final class ChampHashMap[K, +V] private[immutable] (val rootNode: MapNode[K, V], val cachedJavaKeySetHashCode: Int, val cachedSize: Int)
extends AbstractMap[K, V]
with MapOps[K, V, ChampHashMap, ChampHashMap[K, V]]
with StrictOptimizedIterableOps[(K, V), Iterable /* ChampHashMap */, ChampHashMap[K, V]] {
with StrictOptimizedIterableOps[(K, V), Iterable, ChampHashMap[K, V]]
with StrictOptimizedMapOps[K, V, ChampHashMap, ChampHashMap[K, V]] {

override def mapFactory: MapFactory[ChampHashMap] = ChampHashMap

Expand Down
Loading

0 comments on commit 1acaefd

Please sign in to comment.