Skip to content

Commit d97d2c4

Browse files
committed
Capturecheck all files in generic
1 parent 0f9a032 commit d97d2c4

File tree

8 files changed

+610
-13
lines changed

8 files changed

+610
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Scala (https://www.scala-lang.org)
3+
*
4+
* Copyright EPFL and Lightbend, Inc.
5+
*
6+
* Licensed under Apache License 2.0
7+
* (http://www.apache.org/licenses/LICENSE-2.0).
8+
*
9+
* See the NOTICE file distributed with this work for
10+
* additional information regarding copyright ownership.
11+
*/
12+
13+
package scala.collection
14+
package generic
15+
import language.experimental.captureChecking
16+
17+
18+
/** Some bit operations.
19+
*
20+
* See [[https://www.drmaciver.com/2008/08/unsigned-comparison-in-javascala/]] for
21+
* an explanation of unsignedCompare.
22+
*/
23+
private[collection] object BitOperations {
24+
trait Int {
25+
type Int = scala.Int
26+
def zero(i: Int, mask: Int) = (i & mask) == 0
27+
def mask(i: Int, mask: Int) = i & (complement(mask - 1) ^ mask)
28+
def hasMatch(key: Int, prefix: Int, m: Int) = mask(key, m) == prefix
29+
def unsignedCompare(i: Int, j: Int) = (i < j) ^ (i < 0) ^ (j < 0)
30+
def shorter(m1: Int, m2: Int) = unsignedCompare(m2, m1)
31+
def complement(i: Int) = (-1) ^ i
32+
def bits(num: Int) = 31 to 0 by -1 map (i => (num >>> i & 1) != 0)
33+
def bitString(num: Int, sep: String = "") = bits(num) map (b => if (b) "1" else "0") mkString sep
34+
def highestOneBit(j: Int) = java.lang.Integer.highestOneBit(j)
35+
}
36+
object Int extends Int
37+
38+
trait Long {
39+
type Long = scala.Long
40+
def zero(i: Long, mask: Long) = (i & mask) == 0L
41+
def mask(i: Long, mask: Long) = i & (complement(mask - 1) ^ mask)
42+
def hasMatch(key: Long, prefix: Long, m: Long) = mask(key, m) == prefix
43+
def unsignedCompare(i: Long, j: Long) = (i < j) ^ (i < 0L) ^ (j < 0L)
44+
def shorter(m1: Long, m2: Long) = unsignedCompare(m2, m1)
45+
def complement(i: Long) = (-1L) ^ i
46+
def bits(num: Long) = 63L to 0L by -1L map (i => (num >>> i & 1L) != 0L)
47+
def bitString(num: Long, sep: String = "") = bits(num) map (b => if (b) "1" else "0") mkString sep
48+
def highestOneBit(j: Long) = java.lang.Long.highestOneBit(j)
49+
}
50+
object Long extends Long
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Scala (https://www.scala-lang.org)
3+
*
4+
* Copyright EPFL and Lightbend, Inc.
5+
*
6+
* Licensed under Apache License 2.0
7+
* (http://www.apache.org/licenses/LICENSE-2.0).
8+
*
9+
* See the NOTICE file distributed with this work for
10+
* additional information regarding copyright ownership.
11+
*/
12+
13+
package scala.collection.generic
14+
15+
import java.io.{ObjectInputStream, ObjectOutputStream}
16+
17+
import scala.collection.{Factory, Iterable}
18+
import scala.collection.mutable.Builder
19+
import language.experimental.captureChecking
20+
import scala.annotation.unchecked.uncheckedCaptures
21+
22+
/** The default serialization proxy for collection implementations.
23+
*
24+
* This class is `final` and requires an extra `Factory` object rather than leaving the details of creating a `Builder`
25+
* to an abstract method that could be implemented by a subclass. This is necessary because the factory is needed
26+
* for deserializing this class's private state, which happens before any subclass fields would be deserialized. Any
27+
* additional state required to create the proper `Builder` needs to be captured by the `factory`.
28+
*/
29+
@SerialVersionUID(3L)
30+
final class DefaultSerializationProxy[A](factory: Factory[A, Any], @transient private[this] val coll: Iterable[A]) extends Serializable {
31+
32+
@transient protected var builder: Builder[A @uncheckedCaptures, Any] = _
33+
// @uncheckedCaptures OK since builder is used only locally when reading objects
34+
35+
private[this] def writeObject(out: ObjectOutputStream): Unit = {
36+
out.defaultWriteObject()
37+
val k = coll.knownSize
38+
out.writeInt(k)
39+
var count = 0
40+
coll.foreach { x =>
41+
out.writeObject(x)
42+
count += 1
43+
}
44+
if(k >= 0) {
45+
if(count != k) throw new IllegalStateException(s"Illegal size $count of collection, expected $k")
46+
} else out.writeObject(SerializeEnd)
47+
}
48+
49+
private[this] def readObject(in: ObjectInputStream): Unit = {
50+
in.defaultReadObject()
51+
builder = factory.newBuilder
52+
val k = in.readInt()
53+
if(k >= 0) {
54+
builder.sizeHint(k)
55+
var count = 0
56+
while(count < k) {
57+
builder += in.readObject().asInstanceOf[A]
58+
count += 1
59+
}
60+
} else {
61+
while (true) in.readObject match {
62+
case SerializeEnd => return
63+
case a => builder += a.asInstanceOf[A]
64+
}
65+
}
66+
}
67+
68+
protected[this] def readResolve(): Any = builder.result()
69+
}
70+
71+
@SerialVersionUID(3L)
72+
private[collection] case object SerializeEnd
73+
74+
/** Mix-in trait to enable DefaultSerializationProxy for the standard collection types. Depending on the type
75+
* it is mixed into, it will dynamically choose `iterableFactory`, `mapFactory`, `sortedIterableFactory` or
76+
* `sortedMapFactory` for deserialization into the respective `CC` type. Override `writeReplace` or implement
77+
* it directly without using this trait if you need a non-standard factory or if you want to use a different
78+
* serialization scheme.
79+
*/
80+
trait DefaultSerializable extends Serializable { this: scala.collection.Iterable[_] =>
81+
protected[this] def writeReplace(): AnyRef = {
82+
val f: Factory[Any, Any] = this match {
83+
case it: scala.collection.SortedMap[_, _] => it.sortedMapFactory.sortedMapFactory[Any, Any](it.ordering.asInstanceOf[Ordering[Any]]).asInstanceOf[Factory[Any, Any]]
84+
case it: scala.collection.Map[_, _] => it.mapFactory.mapFactory[Any, Any].asInstanceOf[Factory[Any, Any]]
85+
case it: scala.collection.SortedSet[_] => it.sortedIterableFactory.evidenceIterableFactory[Any](it.ordering.asInstanceOf[Ordering[Any]])
86+
case it => it.iterableFactory.iterableFactory
87+
}
88+
new DefaultSerializationProxy(f, this)
89+
}
90+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/*
2+
* Scala (https://www.scala-lang.org)
3+
*
4+
* Copyright EPFL and Lightbend, Inc.
5+
*
6+
* Licensed under Apache License 2.0
7+
* (http://www.apache.org/licenses/LICENSE-2.0).
8+
*
9+
* See the NOTICE file distributed with this work for
10+
* additional information regarding copyright ownership.
11+
*/
12+
13+
package scala.collection
14+
package generic
15+
import language.experimental.captureChecking
16+
17+
/** A trait which can be used to avoid code duplication when defining extension
18+
* methods that should be applicable both to existing Scala collections (i.e.,
19+
* types extending `Iterable`) as well as other (potentially user-defined)
20+
* types that could be converted to a Scala collection type. This trait
21+
* makes it possible to treat Scala collections and types that can be implicitly
22+
* converted to a collection type uniformly. For example, one can provide
23+
* extension methods that work both on collection types and on `String`s (`String`s
24+
* do not extend `Iterable`, but can be converted to `Iterable`)
25+
*
26+
* `IsIterable` provides three members:
27+
*
28+
* 1. type member `A`, which represents the element type of the target `Iterable[A]`
29+
* 1. type member `C`, which represents the type returned by transformation operations that preserve the collection’s elements type
30+
* 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]`.
31+
*
32+
* ===Usage===
33+
*
34+
* One must provide `IsIterable` as an implicit parameter type of an implicit
35+
* conversion. Its usage is shown below. Our objective in the following example
36+
* is to provide a generic extension method `mapReduce` to any type that extends
37+
* or can be converted to `Iterable`. In our example, this includes
38+
* `String`.
39+
*
40+
* {{{
41+
* import scala.collection.{Iterable, IterableOps}
42+
* import scala.collection.generic.IsIterable
43+
*
44+
* class ExtensionMethods[Repr, I <: IsIterable[Repr]](coll: Repr, it: I) {
45+
* def mapReduce[B](mapper: it.A => B)(reducer: (B, B) => B): B = {
46+
* val iter = it(coll).iterator
47+
* var res = mapper(iter.next())
48+
* while (iter.hasNext)
49+
* res = reducer(res, mapper(iter.next()))
50+
* res
51+
* }
52+
* }
53+
*
54+
* implicit def withExtensions[Repr](coll: Repr)(implicit it: IsIterable[Repr]): ExtensionMethods[Repr, it.type] =
55+
* new ExtensionMethods(coll, it)
56+
*
57+
* // See it in action!
58+
* List(1, 2, 3).mapReduce(_ * 2)(_ + _) // res0: Int = 12
59+
* "Yeah, well, you know, that's just, like, your opinion, man.".mapReduce(x => 1)(_ + _) // res1: Int = 59
60+
*}}}
61+
*
62+
* Here, we begin by creating a class `ExtensionMethods` which contains our
63+
* `mapReduce` extension method.
64+
*
65+
* Note that `ExtensionMethods` takes a constructor argument `coll` of type `Repr`, where
66+
* `Repr` represents (typically) the collection type, and an argument `it` of a subtype of `IsIterable[Repr]`.
67+
* The body of the method starts by converting the `coll` argument to an `IterableOps` in order to
68+
* call the `iterator` method on it.
69+
* The remaining of the implementation is straightforward.
70+
*
71+
* The `withExtensions` implicit conversion makes the `mapReduce` operation available
72+
* on any type `Repr` for which it exists an implicit `IsIterable[Repr]` instance.
73+
* Note how we keep track of the precise type of the implicit `it` argument by using the
74+
* `it.type` singleton type, rather than the wider `IsIterable[Repr]` type. We do that
75+
* so that the information carried by the type members `A` and `C` of the `it` argument
76+
* is not lost.
77+
*
78+
* When the `mapReduce` method is called on some type of which it is not
79+
* a member, implicit search is triggered. Because implicit conversion
80+
* `withExtensions` is generic, it will be applied as long as an implicit
81+
* value of type `IsIterable[Repr]` can be found. Given that the
82+
* `IsIterable` companion object contains implicit members that return values of type
83+
* `IsIterable`, this requirement is typically satisfied, and the chain
84+
* of interactions described in the previous paragraph is set into action.
85+
* (See the `IsIterable` companion object, which contains a precise
86+
* specification of the available implicits.)
87+
*
88+
* ''Note'': Currently, it's not possible to combine the implicit conversion and
89+
* the class with the extension methods into an implicit class due to
90+
* limitations of type inference.
91+
*
92+
* ===Implementing `IsIterable` for New Types===
93+
*
94+
* One must simply provide an implicit value of type `IsIterable`
95+
* specific to the new type, or an implicit conversion which returns an
96+
* instance of `IsIterable` specific to the new type.
97+
*
98+
* Below is an example of an implementation of the `IsIterable` trait
99+
* where the `Repr` type is `Range`.
100+
*
101+
*{{{
102+
* implicit val rangeRepr: IsIterable[Range] { type A = Int; type C = IndexedSeq[Int] } =
103+
* new IsIterable[Range] {
104+
* type A = Int
105+
* type C = IndexedSeq[Int]
106+
* def apply(coll: Range): IterableOps[Int, IndexedSeq, IndexedSeq[Int]] = coll
107+
* }
108+
*}}}
109+
*
110+
* (Note that in practice the `IsIterable[Range]` instance is already provided by
111+
* the standard library, and it is defined as an `IsSeq[Range]` instance)
112+
*/
113+
trait IsIterable[Repr] extends IsIterableOnce[Repr] {
114+
115+
/** The type returned by transformation operations that preserve the same elements
116+
* type (e.g. `filter`, `take`).
117+
*
118+
* In practice, this type is often `Repr` itself, excepted in the case
119+
* of `SeqView[A]` (and other `View[A]` subclasses), where it is “only” `View[A]`.
120+
*/
121+
type C
122+
123+
@deprecated("'conversion' is now a method named 'apply'", "2.13.0")
124+
override val conversion: Repr => IterableOps[A, Iterable, C] = apply(_)
125+
126+
/** A conversion from the type `Repr` to `IterableOps[A, Iterable, C]` */
127+
def apply(coll: Repr): IterableOps[A, Iterable, C]
128+
129+
}
130+
131+
object IsIterable extends IsIterableLowPriority {
132+
133+
// Straightforward case: IterableOps subclasses
134+
implicit def iterableOpsIsIterable[A0, CC0[X] <: IterableOps[X, Iterable, CC0[X]]]: IsIterable[CC0[A0]] { type A = A0; type C = CC0[A0] } =
135+
new IsIterable[CC0[A0]] {
136+
type A = A0
137+
type C = CC0[A0]
138+
def apply(coll: CC0[A]): IterableOps[A, Iterable, C] = coll
139+
}
140+
141+
// The `BitSet` type can not be unified with the `CC0` parameter of
142+
// the above definition because it does not take a type parameter.
143+
// Hence the need for a separate case:
144+
implicit def bitSetOpsIsIterable[C0 <: BitSet with BitSetOps[C0]]: IsIterable[C0] { type A = Int; type C = C0 } =
145+
new IsIterable[C0] {
146+
type A = Int
147+
type C = C0
148+
def apply(coll: C0): IterableOps[Int, Iterable, C0] = coll
149+
}
150+
151+
}
152+
153+
trait IsIterableLowPriority {
154+
155+
// Makes `IsSeq` instances visible in `IsIterable` companion
156+
implicit def isSeqLikeIsIterable[Repr](implicit
157+
isSeqLike: IsSeq[Repr]
158+
): IsIterable[Repr] { type A = isSeqLike.A; type C = isSeqLike.C } = isSeqLike
159+
160+
// Makes `IsMap` instances visible in `IsIterable` companion
161+
implicit def isMapLikeIsIterable[Repr](implicit
162+
isMapLike: IsMap[Repr]
163+
): IsIterable[Repr] { type A = isMapLike.A; type C = isMapLike.C } = isMapLike
164+
165+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Scala (https://www.scala-lang.org)
3+
*
4+
* Copyright EPFL and Lightbend, Inc.
5+
*
6+
* Licensed under Apache License 2.0
7+
* (http://www.apache.org/licenses/LICENSE-2.0).
8+
*
9+
* See the NOTICE file distributed with this work for
10+
* additional information regarding copyright ownership.
11+
*/
12+
13+
package scala
14+
package collection
15+
package generic
16+
import language.experimental.captureChecking
17+
18+
/** Type class witnessing that a collection representation type `Repr` has
19+
* elements of type `A` and has a conversion to `IterableOnce[A]`.
20+
*
21+
* This type enables simple enrichment of `IterableOnce`s with extension
22+
* methods which can make full use of the mechanics of the Scala collections
23+
* framework in their implementation.
24+
*
25+
* Example usage,
26+
* {{{
27+
* class FilterMapImpl[Repr, I <: IsIterableOnce[Repr]](coll: Repr, it: I) {
28+
* final def filterMap[B, That](f: it.A => Option[B])(implicit bf: BuildFrom[Repr, B, That]): That = {
29+
* val b = bf.newBuilder(coll)
30+
* for(e <- it(coll).iterator) f(e) foreach (b +=)
31+
* b.result()
32+
* }
33+
* }
34+
* implicit def filterMap[Repr](coll: Repr)(implicit it: IsIterableOnce[Repr]): FilterMapImpl[Repr, it.type] =
35+
* new FilterMapImpl(coll, it)
36+
*
37+
* List(1, 2, 3, 4, 5) filterMap (i => if(i % 2 == 0) Some(i) else None)
38+
* // == List(2, 4)
39+
* }}}
40+
*/
41+
trait IsIterableOnce[Repr] {
42+
43+
/** The type of elements we can traverse over (e.g. `Int`). */
44+
type A
45+
46+
@deprecated("'conversion' is now a method named 'apply'", "2.13.0")
47+
val conversion: Repr => IterableOnce[A] = apply(_)
48+
49+
/** A conversion from the representation type `Repr` to a `IterableOnce[A]`. */
50+
def apply(coll: Repr): IterableOnce[A]
51+
52+
}
53+
54+
object IsIterableOnce extends IsIterableOnceLowPriority {
55+
56+
// Straightforward case: IterableOnce subclasses
57+
implicit def iterableOnceIsIterableOnce[CC0[A] <: IterableOnce[A], A0]: IsIterableOnce[CC0[A0]] { type A = A0 } =
58+
new IsIterableOnce[CC0[A0]] {
59+
type A = A0
60+
def apply(coll: CC0[A0]): IterableOnce[A0] = coll
61+
}
62+
63+
}
64+
65+
trait IsIterableOnceLowPriority {
66+
67+
// Makes `IsIterable` instance visible in `IsIterableOnce` companion
68+
implicit def isIterableLikeIsIterableOnce[Repr](implicit
69+
isIterableLike: IsIterable[Repr]
70+
): IsIterableOnce[Repr] { type A = isIterableLike.A } = isIterableLike
71+
72+
}

0 commit comments

Comments
 (0)