-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
610 additions
and
13 deletions.
There are no files selected for viewing
51 changes: 51 additions & 0 deletions
51
tests/pos-special/stdlib/collection/generic/BitOperations.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/* | ||
* Scala (https://www.scala-lang.org) | ||
* | ||
* Copyright EPFL and Lightbend, Inc. | ||
* | ||
* Licensed under Apache License 2.0 | ||
* (http://www.apache.org/licenses/LICENSE-2.0). | ||
* | ||
* See the NOTICE file distributed with this work for | ||
* additional information regarding copyright ownership. | ||
*/ | ||
|
||
package scala.collection | ||
package generic | ||
import language.experimental.captureChecking | ||
|
||
|
||
/** Some bit operations. | ||
* | ||
* See [[https://www.drmaciver.com/2008/08/unsigned-comparison-in-javascala/]] for | ||
* an explanation of unsignedCompare. | ||
*/ | ||
private[collection] object BitOperations { | ||
trait Int { | ||
type Int = scala.Int | ||
def zero(i: Int, mask: Int) = (i & mask) == 0 | ||
def mask(i: Int, mask: Int) = i & (complement(mask - 1) ^ mask) | ||
def hasMatch(key: Int, prefix: Int, m: Int) = mask(key, m) == prefix | ||
def unsignedCompare(i: Int, j: Int) = (i < j) ^ (i < 0) ^ (j < 0) | ||
def shorter(m1: Int, m2: Int) = unsignedCompare(m2, m1) | ||
def complement(i: Int) = (-1) ^ i | ||
def bits(num: Int) = 31 to 0 by -1 map (i => (num >>> i & 1) != 0) | ||
def bitString(num: Int, sep: String = "") = bits(num) map (b => if (b) "1" else "0") mkString sep | ||
def highestOneBit(j: Int) = java.lang.Integer.highestOneBit(j) | ||
} | ||
object Int extends Int | ||
|
||
trait Long { | ||
type Long = scala.Long | ||
def zero(i: Long, mask: Long) = (i & mask) == 0L | ||
def mask(i: Long, mask: Long) = i & (complement(mask - 1) ^ mask) | ||
def hasMatch(key: Long, prefix: Long, m: Long) = mask(key, m) == prefix | ||
def unsignedCompare(i: Long, j: Long) = (i < j) ^ (i < 0L) ^ (j < 0L) | ||
def shorter(m1: Long, m2: Long) = unsignedCompare(m2, m1) | ||
def complement(i: Long) = (-1L) ^ i | ||
def bits(num: Long) = 63L to 0L by -1L map (i => (num >>> i & 1L) != 0L) | ||
def bitString(num: Long, sep: String = "") = bits(num) map (b => if (b) "1" else "0") mkString sep | ||
def highestOneBit(j: Long) = java.lang.Long.highestOneBit(j) | ||
} | ||
object Long extends Long | ||
} |
90 changes: 90 additions & 0 deletions
90
tests/pos-special/stdlib/collection/generic/DefaultSerializationProxy.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/* | ||
* Scala (https://www.scala-lang.org) | ||
* | ||
* Copyright EPFL and Lightbend, Inc. | ||
* | ||
* Licensed under Apache License 2.0 | ||
* (http://www.apache.org/licenses/LICENSE-2.0). | ||
* | ||
* See the NOTICE file distributed with this work for | ||
* additional information regarding copyright ownership. | ||
*/ | ||
|
||
package scala.collection.generic | ||
|
||
import java.io.{ObjectInputStream, ObjectOutputStream} | ||
|
||
import scala.collection.{Factory, Iterable} | ||
import scala.collection.mutable.Builder | ||
import language.experimental.captureChecking | ||
import scala.annotation.unchecked.uncheckedCaptures | ||
|
||
/** The default serialization proxy for collection implementations. | ||
* | ||
* This class is `final` and requires an extra `Factory` object rather than leaving the details of creating a `Builder` | ||
* to an abstract method that could be implemented by a subclass. This is necessary because the factory is needed | ||
* for deserializing this class's private state, which happens before any subclass fields would be deserialized. Any | ||
* additional state required to create the proper `Builder` needs to be captured by the `factory`. | ||
*/ | ||
@SerialVersionUID(3L) | ||
final class DefaultSerializationProxy[A](factory: Factory[A, Any], @transient private[this] val coll: Iterable[A]) extends Serializable { | ||
|
||
@transient protected var builder: Builder[A @uncheckedCaptures, Any] = _ | ||
// @uncheckedCaptures OK since builder is used only locally when reading objects | ||
|
||
private[this] def writeObject(out: ObjectOutputStream): Unit = { | ||
out.defaultWriteObject() | ||
val k = coll.knownSize | ||
out.writeInt(k) | ||
var count = 0 | ||
coll.foreach { x => | ||
out.writeObject(x) | ||
count += 1 | ||
} | ||
if(k >= 0) { | ||
if(count != k) throw new IllegalStateException(s"Illegal size $count of collection, expected $k") | ||
} else out.writeObject(SerializeEnd) | ||
} | ||
|
||
private[this] def readObject(in: ObjectInputStream): Unit = { | ||
in.defaultReadObject() | ||
builder = factory.newBuilder | ||
val k = in.readInt() | ||
if(k >= 0) { | ||
builder.sizeHint(k) | ||
var count = 0 | ||
while(count < k) { | ||
builder += in.readObject().asInstanceOf[A] | ||
count += 1 | ||
} | ||
} else { | ||
while (true) in.readObject match { | ||
case SerializeEnd => return | ||
case a => builder += a.asInstanceOf[A] | ||
} | ||
} | ||
} | ||
|
||
protected[this] def readResolve(): Any = builder.result() | ||
} | ||
|
||
@SerialVersionUID(3L) | ||
private[collection] case object SerializeEnd | ||
|
||
/** Mix-in trait to enable DefaultSerializationProxy for the standard collection types. Depending on the type | ||
* it is mixed into, it will dynamically choose `iterableFactory`, `mapFactory`, `sortedIterableFactory` or | ||
* `sortedMapFactory` for deserialization into the respective `CC` type. Override `writeReplace` or implement | ||
* it directly without using this trait if you need a non-standard factory or if you want to use a different | ||
* serialization scheme. | ||
*/ | ||
trait DefaultSerializable extends Serializable { this: scala.collection.Iterable[_] => | ||
protected[this] def writeReplace(): AnyRef = { | ||
val f: Factory[Any, Any] = this match { | ||
case it: scala.collection.SortedMap[_, _] => it.sortedMapFactory.sortedMapFactory[Any, Any](it.ordering.asInstanceOf[Ordering[Any]]).asInstanceOf[Factory[Any, Any]] | ||
case it: scala.collection.Map[_, _] => it.mapFactory.mapFactory[Any, Any].asInstanceOf[Factory[Any, Any]] | ||
case it: scala.collection.SortedSet[_] => it.sortedIterableFactory.evidenceIterableFactory[Any](it.ordering.asInstanceOf[Ordering[Any]]) | ||
case it => it.iterableFactory.iterableFactory | ||
} | ||
new DefaultSerializationProxy(f, this) | ||
} | ||
} |
165 changes: 165 additions & 0 deletions
165
tests/pos-special/stdlib/collection/generic/IsIterable.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
/* | ||
* Scala (https://www.scala-lang.org) | ||
* | ||
* Copyright EPFL and Lightbend, Inc. | ||
* | ||
* Licensed under Apache License 2.0 | ||
* (http://www.apache.org/licenses/LICENSE-2.0). | ||
* | ||
* See the NOTICE file distributed with this work for | ||
* additional information regarding copyright ownership. | ||
*/ | ||
|
||
package scala.collection | ||
package generic | ||
import language.experimental.captureChecking | ||
|
||
/** A trait which can be used to avoid code duplication when defining extension | ||
* methods that should be applicable both to existing Scala collections (i.e., | ||
* types extending `Iterable`) as well as other (potentially user-defined) | ||
* types that could be converted to a Scala collection type. This trait | ||
* makes it possible to treat Scala collections and types that can be implicitly | ||
* converted to a collection type uniformly. For example, one can provide | ||
* extension methods that work both on collection types and on `String`s (`String`s | ||
* do not extend `Iterable`, but can be converted to `Iterable`) | ||
* | ||
* `IsIterable` provides three members: | ||
* | ||
* 1. type member `A`, which represents the element type of the target `Iterable[A]` | ||
* 1. type member `C`, which represents the type returned by transformation operations that preserve the collection’s elements type | ||
* 1. method `apply`, which provides a way to convert between the type we wish to add extension methods to, `Repr`, and `IterableOps[A, Iterable, C]`. | ||
* | ||
* ===Usage=== | ||
* | ||
* One must provide `IsIterable` as an implicit parameter type of an implicit | ||
* conversion. Its usage is shown below. Our objective in the following example | ||
* is to provide a generic extension method `mapReduce` to any type that extends | ||
* or can be converted to `Iterable`. In our example, this includes | ||
* `String`. | ||
* | ||
* {{{ | ||
* import scala.collection.{Iterable, IterableOps} | ||
* import scala.collection.generic.IsIterable | ||
* | ||
* class ExtensionMethods[Repr, I <: IsIterable[Repr]](coll: Repr, it: I) { | ||
* def mapReduce[B](mapper: it.A => B)(reducer: (B, B) => B): B = { | ||
* val iter = it(coll).iterator | ||
* var res = mapper(iter.next()) | ||
* while (iter.hasNext) | ||
* res = reducer(res, mapper(iter.next())) | ||
* res | ||
* } | ||
* } | ||
* | ||
* implicit def withExtensions[Repr](coll: Repr)(implicit it: IsIterable[Repr]): ExtensionMethods[Repr, it.type] = | ||
* new ExtensionMethods(coll, it) | ||
* | ||
* // See it in action! | ||
* List(1, 2, 3).mapReduce(_ * 2)(_ + _) // res0: Int = 12 | ||
* "Yeah, well, you know, that's just, like, your opinion, man.".mapReduce(x => 1)(_ + _) // res1: Int = 59 | ||
*}}} | ||
* | ||
* Here, we begin by creating a class `ExtensionMethods` which contains our | ||
* `mapReduce` extension method. | ||
* | ||
* Note that `ExtensionMethods` takes a constructor argument `coll` of type `Repr`, where | ||
* `Repr` represents (typically) the collection type, and an argument `it` of a subtype of `IsIterable[Repr]`. | ||
* The body of the method starts by converting the `coll` argument to an `IterableOps` in order to | ||
* call the `iterator` method on it. | ||
* The remaining of the implementation is straightforward. | ||
* | ||
* The `withExtensions` implicit conversion makes the `mapReduce` operation available | ||
* on any type `Repr` for which it exists an implicit `IsIterable[Repr]` instance. | ||
* Note how we keep track of the precise type of the implicit `it` argument by using the | ||
* `it.type` singleton type, rather than the wider `IsIterable[Repr]` type. We do that | ||
* so that the information carried by the type members `A` and `C` of the `it` argument | ||
* is not lost. | ||
* | ||
* When the `mapReduce` method is called on some type of which it is not | ||
* a member, implicit search is triggered. Because implicit conversion | ||
* `withExtensions` is generic, it will be applied as long as an implicit | ||
* value of type `IsIterable[Repr]` can be found. Given that the | ||
* `IsIterable` companion object contains implicit members that return values of type | ||
* `IsIterable`, this requirement is typically satisfied, and the chain | ||
* of interactions described in the previous paragraph is set into action. | ||
* (See the `IsIterable` companion object, which contains a precise | ||
* specification of the available implicits.) | ||
* | ||
* ''Note'': Currently, it's not possible to combine the implicit conversion and | ||
* the class with the extension methods into an implicit class due to | ||
* limitations of type inference. | ||
* | ||
* ===Implementing `IsIterable` for New Types=== | ||
* | ||
* One must simply provide an implicit value of type `IsIterable` | ||
* specific to the new type, or an implicit conversion which returns an | ||
* instance of `IsIterable` specific to the new type. | ||
* | ||
* Below is an example of an implementation of the `IsIterable` trait | ||
* where the `Repr` type is `Range`. | ||
* | ||
*{{{ | ||
* implicit val rangeRepr: IsIterable[Range] { type A = Int; type C = IndexedSeq[Int] } = | ||
* new IsIterable[Range] { | ||
* type A = Int | ||
* type C = IndexedSeq[Int] | ||
* def apply(coll: Range): IterableOps[Int, IndexedSeq, IndexedSeq[Int]] = coll | ||
* } | ||
*}}} | ||
* | ||
* (Note that in practice the `IsIterable[Range]` instance is already provided by | ||
* the standard library, and it is defined as an `IsSeq[Range]` instance) | ||
*/ | ||
trait IsIterable[Repr] extends IsIterableOnce[Repr] { | ||
|
||
/** The type returned by transformation operations that preserve the same elements | ||
* type (e.g. `filter`, `take`). | ||
* | ||
* In practice, this type is often `Repr` itself, excepted in the case | ||
* of `SeqView[A]` (and other `View[A]` subclasses), where it is “only” `View[A]`. | ||
*/ | ||
type C | ||
|
||
@deprecated("'conversion' is now a method named 'apply'", "2.13.0") | ||
override val conversion: Repr => IterableOps[A, Iterable, C] = apply(_) | ||
|
||
/** A conversion from the type `Repr` to `IterableOps[A, Iterable, C]` */ | ||
def apply(coll: Repr): IterableOps[A, Iterable, C] | ||
|
||
} | ||
|
||
object IsIterable extends IsIterableLowPriority { | ||
|
||
// Straightforward case: IterableOps subclasses | ||
implicit def iterableOpsIsIterable[A0, CC0[X] <: IterableOps[X, Iterable, CC0[X]]]: IsIterable[CC0[A0]] { type A = A0; type C = CC0[A0] } = | ||
new IsIterable[CC0[A0]] { | ||
type A = A0 | ||
type C = CC0[A0] | ||
def apply(coll: CC0[A]): IterableOps[A, Iterable, C] = coll | ||
} | ||
|
||
// The `BitSet` type can not be unified with the `CC0` parameter of | ||
// the above definition because it does not take a type parameter. | ||
// Hence the need for a separate case: | ||
implicit def bitSetOpsIsIterable[C0 <: BitSet with BitSetOps[C0]]: IsIterable[C0] { type A = Int; type C = C0 } = | ||
new IsIterable[C0] { | ||
type A = Int | ||
type C = C0 | ||
def apply(coll: C0): IterableOps[Int, Iterable, C0] = coll | ||
} | ||
|
||
} | ||
|
||
trait IsIterableLowPriority { | ||
|
||
// Makes `IsSeq` instances visible in `IsIterable` companion | ||
implicit def isSeqLikeIsIterable[Repr](implicit | ||
isSeqLike: IsSeq[Repr] | ||
): IsIterable[Repr] { type A = isSeqLike.A; type C = isSeqLike.C } = isSeqLike | ||
|
||
// Makes `IsMap` instances visible in `IsIterable` companion | ||
implicit def isMapLikeIsIterable[Repr](implicit | ||
isMapLike: IsMap[Repr] | ||
): IsIterable[Repr] { type A = isMapLike.A; type C = isMapLike.C } = isMapLike | ||
|
||
} |
72 changes: 72 additions & 0 deletions
72
tests/pos-special/stdlib/collection/generic/IsIterableOnce.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/* | ||
* Scala (https://www.scala-lang.org) | ||
* | ||
* Copyright EPFL and Lightbend, Inc. | ||
* | ||
* Licensed under Apache License 2.0 | ||
* (http://www.apache.org/licenses/LICENSE-2.0). | ||
* | ||
* See the NOTICE file distributed with this work for | ||
* additional information regarding copyright ownership. | ||
*/ | ||
|
||
package scala | ||
package collection | ||
package generic | ||
import language.experimental.captureChecking | ||
|
||
/** Type class witnessing that a collection representation type `Repr` has | ||
* elements of type `A` and has a conversion to `IterableOnce[A]`. | ||
* | ||
* This type enables simple enrichment of `IterableOnce`s with extension | ||
* methods which can make full use of the mechanics of the Scala collections | ||
* framework in their implementation. | ||
* | ||
* Example usage, | ||
* {{{ | ||
* class FilterMapImpl[Repr, I <: IsIterableOnce[Repr]](coll: Repr, it: I) { | ||
* final def filterMap[B, That](f: it.A => Option[B])(implicit bf: BuildFrom[Repr, B, That]): That = { | ||
* val b = bf.newBuilder(coll) | ||
* for(e <- it(coll).iterator) f(e) foreach (b +=) | ||
* b.result() | ||
* } | ||
* } | ||
* implicit def filterMap[Repr](coll: Repr)(implicit it: IsIterableOnce[Repr]): FilterMapImpl[Repr, it.type] = | ||
* new FilterMapImpl(coll, it) | ||
* | ||
* List(1, 2, 3, 4, 5) filterMap (i => if(i % 2 == 0) Some(i) else None) | ||
* // == List(2, 4) | ||
* }}} | ||
*/ | ||
trait IsIterableOnce[Repr] { | ||
|
||
/** The type of elements we can traverse over (e.g. `Int`). */ | ||
type A | ||
|
||
@deprecated("'conversion' is now a method named 'apply'", "2.13.0") | ||
val conversion: Repr => IterableOnce[A] = apply(_) | ||
|
||
/** A conversion from the representation type `Repr` to a `IterableOnce[A]`. */ | ||
def apply(coll: Repr): IterableOnce[A] | ||
|
||
} | ||
|
||
object IsIterableOnce extends IsIterableOnceLowPriority { | ||
|
||
// Straightforward case: IterableOnce subclasses | ||
implicit def iterableOnceIsIterableOnce[CC0[A] <: IterableOnce[A], A0]: IsIterableOnce[CC0[A0]] { type A = A0 } = | ||
new IsIterableOnce[CC0[A0]] { | ||
type A = A0 | ||
def apply(coll: CC0[A0]): IterableOnce[A0] = coll | ||
} | ||
|
||
} | ||
|
||
trait IsIterableOnceLowPriority { | ||
|
||
// Makes `IsIterable` instance visible in `IsIterableOnce` companion | ||
implicit def isIterableLikeIsIterableOnce[Repr](implicit | ||
isIterableLike: IsIterable[Repr] | ||
): IsIterableOnce[Repr] { type A = isIterableLike.A } = isIterableLike | ||
|
||
} |
Oops, something went wrong.