@@ -3,6 +3,7 @@ package strawman.collections
3
3
import Predef .{augmentString => _ , wrapString => _ , _ }
4
4
import scala .reflect .ClassTag
5
5
import annotation .unchecked .uncheckedVariance
6
+ import annotation .tailrec
6
7
7
8
/** A strawman architecture for new collections. It contains some
8
9
* example collection classes and methods with the intent to expose
@@ -32,24 +33,8 @@ object CollectionStrawMan5 {
32
33
def apply [A ](xs : A * ): C [A ] = fromIterable(View .Elems (xs : _* ))
33
34
}
34
35
35
- /** Base trait for Iterable operations */
36
- trait IterableLike [+ A , + C [X ] <: Iterable [X ]]
37
- extends FromIterable [C ]
38
- with IterableOps [A ]
39
- with IterableMonoTransforms [A @ uncheckedVariance, C [A @ uncheckedVariance]]
40
- with IterablePolyTransforms [A @ uncheckedVariance, C ] {
41
- protected [this ] def fromLikeIterable (coll : Iterable [A ]): C [A ] = fromIterable(coll)
42
- }
43
-
44
- /** Base trait for Seq operations */
45
- trait SeqLike [+ A , + C [X ] <: Seq [X ]]
46
- extends IterableLike [A , C ] with SeqMonoTransforms [A @ uncheckedVariance, C [A @ uncheckedVariance]]
47
-
48
36
/** Base trait for generic collections */
49
37
trait Iterable [+ A ] extends IterableOnce [A ] with IterableLike [A , Iterable ] {
50
- override def iterator : Iterator [A ]
51
- override def fromIterable [B ](it : Iterable [B ]): Iterable [B ]
52
-
53
38
protected def coll : Iterable [A ] = this
54
39
def knownLength : Int = - 1
55
40
}
@@ -58,18 +43,21 @@ object CollectionStrawMan5 {
58
43
trait Seq [+ A ] extends Iterable [A ] with SeqLike [A , Seq ] {
59
44
def apply (i : Int ): A
60
45
def length : Int
61
- override def iterator : Iterator [A ]
62
46
}
63
47
48
+ /** Base trait for strict collections */
64
49
trait Buildable [+ A , + To <: Iterable [A ]] extends Iterable [A ] {
65
50
protected [this ] def newBuilder : Builder [A , To ]
66
51
override def partition (p : A => Boolean ): (To , To ) = {
67
52
val l, r = newBuilder
68
53
iterator.foreach(x => (if (p(x)) l else r) += x)
69
54
(l.result, r.result)
70
55
}
56
+ // one might also override other transforms here to avoid generating
57
+ // iterators if it helps efficiency.
71
58
}
72
59
60
+ /** Base trait for collection builders */
73
61
trait Builder [- A , + To ] {
74
62
def += (x : A ): this .type
75
63
def result : To
@@ -82,6 +70,29 @@ object CollectionStrawMan5 {
82
70
83
71
/* ------------ Operations ----------------------------------- */
84
72
73
+ /** Base trait for Iterable operations
74
+ *
75
+ * VarianceNote
76
+ * ============
77
+ *
78
+ * We require that for all child classes of Iterable the variance of
79
+ * the child class and the variance of the `C` parameter passed to `IterableLike`
80
+ * are the same. We cannot express this since we lack variance polymorphism. That's
81
+ * why we have to resort at some places to write `C[A @uncheckedVariance]`.
82
+ *
83
+ */
84
+ trait IterableLike [+ A , + C [X ] <: Iterable [X ]]
85
+ extends FromIterable [C ]
86
+ with IterableOps [A ]
87
+ with IterableMonoTransforms [A , C [A @ uncheckedVariance]] // sound bcs of VarianceNote
88
+ with IterablePolyTransforms [A , C ] {
89
+ protected [this ] def fromLikeIterable (coll : Iterable [A ]): C [A ] = fromIterable(coll)
90
+ }
91
+
92
+ /** Base trait for Seq operations */
93
+ trait SeqLike [+ A , + C [X ] <: Seq [X ]]
94
+ extends IterableLike [A , C ] with SeqMonoTransforms [A , C [A @ uncheckedVariance]] // sound bcs of VarianceNote
95
+
85
96
trait IterableOps [+ A ] extends Any {
86
97
def iterator : Iterator [A ]
87
98
def foreach (f : A => Unit ): Unit = iterator.foreach(f)
@@ -93,16 +104,19 @@ object CollectionStrawMan5 {
93
104
def view : View [A ] = View .fromIterator(iterator)
94
105
}
95
106
96
- trait IterableMonoTransforms [A , + Repr ] extends Any {
107
+ trait IterableMonoTransforms [+ A , + Repr ] extends Any {
97
108
protected def coll : Iterable [A ]
98
- protected def fromLikeIterable (coll : Iterable [A ]): Repr
109
+ protected [ this ] def fromLikeIterable (coll : Iterable [A ]): Repr
99
110
def filter (p : A => Boolean ): Repr = fromLikeIterable(View .Filter (coll, p))
100
111
def partition (p : A => Boolean ): (Repr , Repr ) = {
101
112
val pn = View .Partition (coll, p)
102
113
(fromLikeIterable(pn.left), fromLikeIterable(pn.right))
103
114
}
104
115
def drop (n : Int ): Repr = fromLikeIterable(View .Drop (coll, n))
105
- def to [C [X ] <: Iterable [X ]](fi : FromIterable [C ]): C [A ] = fi.fromIterable(coll)
116
+ def to [C [X ] <: Iterable [X ]](fi : FromIterable [C ]): C [A @ uncheckedVariance] =
117
+ // variance seems sound because `to` could just as well have been added
118
+ // as a decorator. We should investigate this further to be sure.
119
+ fi.fromIterable(coll)
106
120
}
107
121
108
122
trait IterablePolyTransforms [+ A , + C [A ]] extends Any {
@@ -112,9 +126,10 @@ object CollectionStrawMan5 {
112
126
def flatMap [B ](f : A => IterableOnce [B ]): C [B ] = fromIterable(View .FlatMap (coll, f))
113
127
def ++ [B >: A ](xs : IterableOnce [B ]): C [B ] = fromIterable(View .Concat (coll, xs))
114
128
def zip [B ](xs : IterableOnce [B ]): C [(A @ uncheckedVariance, B )] = fromIterable(View .Zip (coll, xs))
129
+ // sound bcs of VarianceNote
115
130
}
116
131
117
- trait SeqMonoTransforms [A , + Repr ] extends Any with IterableMonoTransforms [A , Repr ] {
132
+ trait SeqMonoTransforms [+ A , + Repr ] extends Any with IterableMonoTransforms [A , Repr ] {
118
133
def reverse : Repr = {
119
134
var xs : List [A ] = Nil
120
135
var it = coll.iterator
@@ -150,10 +165,12 @@ object CollectionStrawMan5 {
150
165
case xs : List [B ] => this ++: xs
151
166
case _ => super .++ (xs)
152
167
}
153
- override def reverse = super .reverse
168
+ @ tailrec final override def drop (n : Int ) =
169
+ if (n > 0 ) tail.drop(n - 1 ) else this
154
170
}
155
171
156
- case class Cons [+ A ](x : A , private [collections] var next : List [A @ uncheckedVariance]) extends List [A ] {
172
+ case class Cons [+ A ](x : A , private [collections] var next : List [A @ uncheckedVariance]) // sound because `next` is used only locally
173
+ extends List [A ] {
157
174
override def isEmpty = false
158
175
override def head = x
159
176
def tail = next
@@ -176,11 +193,7 @@ object CollectionStrawMan5 {
176
193
class ListBuffer [A ] extends Seq [A ] with SeqLike [A , ListBuffer ] with Builder [A , List [A ]] {
177
194
private var first, last : List [A ] = Nil
178
195
private var aliased = false
179
- def iterator = new Iterator [A ] {
180
- var current : List [A ] = first
181
- def hasNext = ???
182
- def next = ???
183
- }
196
+ def iterator = first.iterator
184
197
def fromIterable [B ](coll : Iterable [B ]) = ListBuffer .fromIterable(coll)
185
198
def apply (i : Int ) = first.apply(i)
186
199
def length = first.length
@@ -205,6 +218,12 @@ object CollectionStrawMan5 {
205
218
last = last1
206
219
this
207
220
}
221
+ override def toString : String =
222
+ if (first.isEmpty) " ListBuffer()"
223
+ else {
224
+ val b = new StringBuilder (" ListBuffer(" ).append(first.head)
225
+ first.tail.foldLeft(b)(_.append(" , " ).append(_)).append(" )" ).toString
226
+ }
208
227
}
209
228
210
229
object ListBuffer extends IterableFactory [ListBuffer ] {
@@ -291,12 +310,12 @@ object CollectionStrawMan5 {
291
310
def fromIterable [B ](coll : Iterable [B ]): List [B ] = List .fromIterable(coll)
292
311
def map (f : Char => Char ): String = {
293
312
val sb = new StringBuilder
294
- for (ch <- StringOps (s) ) sb.append(f(ch))
313
+ for (ch <- s ) sb.append(f(ch))
295
314
sb.toString
296
315
}
297
316
def flatMap (f : Char => String ): String = {
298
317
val sb = new StringBuilder
299
- for (ch <- StringOps (s) ) sb.append(f(ch))
318
+ for (ch <- s ) sb.append(f(ch))
300
319
sb.toString
301
320
}
302
321
def ++ (xs : IterableOnce [Char ]): String = {
@@ -393,15 +412,6 @@ object CollectionStrawMan5 {
393
412
- 1
394
413
}
395
414
}
396
- case class Reverse [A ](underlying : Iterable [A ]) extends View [A ] {
397
- def iterator = {
398
- var xs : List [A ] = Nil
399
- val it = underlying.iterator
400
- while (it.hasNext) xs = Cons (it.next(), xs)
401
- xs.iterator
402
- }
403
- override def knownLength = underlying.knownLength
404
- }
405
415
}
406
416
407
417
/* ---------- Iterators ---------------------------------------------------*/
0 commit comments