@@ -124,28 +124,36 @@ object CollectionStrawMan6 extends LowPriority {
124
124
def length : Int
125
125
}
126
126
127
- /** Base trait for linearly accessed sequences */
128
- trait LinearSeq [+ A ] extends Seq [A ] with SeqLike [A , LinearSeq ] { self =>
127
+ /** Base trait for linearly accessed sequences that have efficient `head` and
128
+ * `tail` operations.
129
+ * Known subclasses: List, LazyList
130
+ */
131
+ trait LinearSeq [+ A ] extends Seq [A ] with LinearSeqLike [A , LinearSeq ] { self =>
129
132
130
133
/** To be overridden in implementations: */
131
134
def isEmpty : Boolean
132
135
def head : A
133
136
def tail : LinearSeq [A ]
134
137
138
+ /** `iterator` is overridden in terms of `head` and `tail` */
135
139
def iterator = new Iterator [A ] {
136
140
private [this ] var current : Seq [A ] = self
137
141
def hasNext = ! current.isEmpty
138
142
def next = { val r = current.head; current = current.tail; r }
139
143
}
140
144
145
+ /** `length is defined in terms of `iterator` */
141
146
def length : Int = iterator.length
142
147
143
- @ tailrec final def apply (n : Int ): A =
144
- if (n == 0 ) head else tail.apply(n - 1 )
145
-
146
- /** Optimized version of `drop` that avoids copying */
147
- @ tailrec final override def drop (n : Int ) =
148
- if (n <= 0 ) this else tail.drop(n - 1 )
148
+ /** `apply` is defined in terms of `drop`, which is in turn defined in
149
+ * terms of `tail`.
150
+ */
151
+ override def apply (n : Int ): A = {
152
+ if (n < 0 ) throw new IndexOutOfBoundsException (n.toString)
153
+ val skipped = drop(n)
154
+ if (skipped.isEmpty) throw new IndexOutOfBoundsException (n.toString)
155
+ skipped.head
156
+ }
149
157
}
150
158
151
159
/** Base trait for strict collections that can be built using a builder.
@@ -221,6 +229,28 @@ object CollectionStrawMan6 extends LowPriority {
221
229
extends IterableLike [A , C ]
222
230
with SeqMonoTransforms [A , C [A @ uncheckedVariance]] // sound bcs of VarianceNote
223
231
232
+ /** Base trait for linear Seq operations */
233
+ trait LinearSeqLike [+ A , + C [X ] <: LinearSeq [X ]] extends SeqLike [A , C ] {
234
+
235
+ /** Optimized version of `drop` that avoids copying
236
+ * Note: `drop` is defined here, rather than in a trait like `LinearSeqMonoTransforms`,
237
+ * because the `...MonoTransforms` traits make no assumption about the type of `Repr`
238
+ * whereas we need to assume here that `Repr` is the same as the underlying
239
+ * collection type.
240
+ */
241
+ override def drop (n : Int ): C [A @ uncheckedVariance] = { // sound bcs of VarianceNote
242
+ def loop (n : Int , s : Iterable [A ]): C [A ] =
243
+ if (n <= 0 ) s.asInstanceOf [C [A ]]
244
+ // implicit contract to guarantee success of asInstanceOf:
245
+ // (1) coll is of type C[A]
246
+ // (2) The tail of a LinearSeq is of the same type as the type of the sequence itself
247
+ // it's surprisingly tricky/ugly to turn this into actual types, so we
248
+ // leave this contract implicit.
249
+ else loop(n - 1 , s.tail)
250
+ loop(n, coll)
251
+ }
252
+ }
253
+
224
254
/** Operations over iterables. No operation defined here is generic in the
225
255
* type of the underlying collection.
226
256
*/
0 commit comments