aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/strawman/collections/CollectionStrawMan1.scala
blob: c127757ad539a7654b4dcc728066bef808ad489a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
package strawman.collections

import Predef.{augmentString => _, wrapString => _, _}
import scala.reflect.ClassTag

/** A strawman architecture for new collections. It contains some
 *  example collection classes and methods with the intent to expose
 *  some key issues. It would be good to compare this to other
 *  implementations of the same functionality, to get an idea of the
 *  strengths and weaknesses of different collection architectures.
 *
 *  For a test file, see tests/run/CollectionTests.scala.
 */
object CollectionStrawMan1 {

  /* ------------ Base Traits -------------------------------- */

  /** Replaces TraversableOnce */
  trait CanIterate[+A] {
    def iterator: Iterator[A]
  }

  /** Base trait for instances that can construct a collection from an iterator */
  trait FromIterator[+C[X] <: Iterable[X]] {
    def fromIterator[B](it: Iterator[B]): C[B]
  }

  /** Base trait for companion objects of collections */
  trait IterableFactory[+C[X] <: Iterable[X]] extends FromIterator[C] {
    def empty[X]: C[X] = fromIterator(Iterator.empty)
    def apply[A](xs: A*): C[A] = fromIterator(Iterator(xs: _*))
  }

  /** Base trait for generic collections */
  trait Iterable[+A] extends CanIterate[A] with FromIterator[Iterable]

  /** Base trait for sequence collections */
  trait Seq[+A] extends Iterable[A] with FromIterator[Seq] {
    def apply(i: Int): A
    def length: Int
  }

  /* ------------ Operations ----------------------------------- */

  /** Operations returning types unrelated to current collection */
  trait Ops[A] extends Any {
    def iterator: Iterator[A]
    def foreach(f: A => Unit): Unit = iterator.foreach(f)
    def foldLeft[B](z: B)(op: (B, A) => B): B = iterator.foldLeft(z)(op)
    def foldRight[B](z: B)(op: (A, B) => B): B = iterator.foldRight(z)(op)
    def indexWhere(p: A => Boolean): Int = iterator.indexWhere(p)
    def isEmpty: Boolean = !iterator.hasNext
    def head: A = iterator.next
    def view: View[A] = new View(iterator)
    def to[C[X] <: Iterable[X]](fi: FromIterator[C]): C[A] = fi.fromIterator(iterator)
  }

  /** Transforms returning same collection type */
  trait MonoTransforms[A, Repr] extends Any {
    protected def iter: Iterator[A]
    protected def fromIter(it: => Iterator[A]): Repr
    def partition(p: A => Boolean): (Repr, Repr) = {
      val (xs, ys) = iter.partition(p)
      (fromIter(xs), fromIter(ys))
    }
    def drop(n: Int): Repr = fromIter(iter.drop(n))
  }

  /** Transforms returning same collection type constructor */
  trait PolyTransforms[A, C[X]] extends Any {
    protected def iter: Iterator[A]
    protected def fromIter[B](it: => Iterator[B]): C[B]
    def map[B](f: A => B): C[B] = fromIter(iter.map(f))
    def flatMap[B](f: A => CanIterate[B]): C[B] = fromIter(iter.flatMap(f(_)))
    def ++[B >: A](xs: CanIterate[B]): C[B] = fromIter(iter ++ xs)
    def zip[B](xs: CanIterate[B]): C[(A, B)] = fromIter(iter.zip(xs.iterator))
  }

  /** Transforms that only apply to Seq */
  trait MonoTransformsOfSeqs[A, Repr] extends Any with MonoTransforms[A, Repr] {
    def reverse: Repr = fromIter(iter.reverse)
  }

  /** Implementation of Ops for all generic collections */
  implicit class IterableOps[A](val c: Iterable[A])
  extends AnyVal with Ops[A] {
    def iterator = c.iterator
  }

  /** Implementation of MonoTransforms for all generic collections */
  implicit class IterableMonoTransforms[A, C[X] <: Iterable[X]](val c: Iterable[A] with FromIterator[C])
  extends AnyVal with MonoTransforms[A, C[A]] {
    protected def iter = c.iterator
    protected def fromIter(it: => Iterator[A]): C[A] = c.fromIterator(it)
  }

  /** Implementation of PolyTransforms for all generic collections */
  implicit class IterablePolyTransforms[A, C[X] <: Iterable[X]](val c: Iterable[A] with FromIterator[C])
  extends AnyVal with PolyTransforms[A, C] {
    protected def iter = c.iterator
    protected def fromIter[B](it: => Iterator[B]) = c.fromIterator(it)
  }

  /** Implementation of MonoTransformsForSeqs for all generic collections */
  implicit class SeqMonoTransforms[A, C[X] <: Seq[X]](val c: Seq[A] with FromIterator[C])
  extends AnyVal with MonoTransformsOfSeqs[A, C[A]] {
    protected def iter = c.iterator
    protected def fromIter(it: => Iterator[A]) = c.fromIterator(it)
  }

  /* --------- Concrete collection types ------------------------------- */

  /** Concrete collection type: List */
  sealed trait List[+A] extends Seq[A] with FromIterator[List] {
    def isEmpty: Boolean
    def head: A
    def tail: List[A]
    def iterator = new ListIterator[A](this)
    def fromIterator[B](it: Iterator[B]): List[B] = List.fromIterator(it)
    def apply(i: Int): A = {
      require(!isEmpty)
      if (i == 0) head else tail.apply(i - 1)
    }
    def length: Int =
      if (isEmpty) 0 else 1 + tail.length
  }

  case class Cons[+A](x: A, xs: List[A]) extends List[A] {
    def isEmpty = false
    def head = x
    def tail = xs
  }

  case object Nil extends List[Nothing] {
    def isEmpty = true
    def head = ???
    def tail = ???
  }

  object List extends IterableFactory[List] {
    def fromIterator[B](it: Iterator[B]): List[B] = it match {
      case it: ListIterator[B] => it.toList
      case _ => if (it.hasNext) Cons(it.next, fromIterator(it)) else Nil
    }
  }

  class ListIterator[+A](xs: List[A]) extends Iterator[A] {
    private[this] var current = xs
    def hasNext = !current.isEmpty
    def next = { val r = current.head; current = current.tail; r }
    def toList = current
  }

  /** Concrete collection type: ArrayBuffer */
  class ArrayBuffer[A] private (initElems: Array[AnyRef], initLength: Int) extends Seq[A] with FromIterator[ArrayBuffer] {
    def this() = this(new Array[AnyRef](16), 0)
    private var elems: Array[AnyRef] = initElems
    private var start = 0
    private var limit = initLength
    def apply(i: Int) = elems(start + i).asInstanceOf[A]
    def length = limit - start
    def iterator = new ArrayBufferIterator[A](elems, start, length)
    def fromIterator[B](it: Iterator[B]): ArrayBuffer[B] =
      ArrayBuffer.fromIterator(it)
    def +=(elem: A): this.type = {
      if (limit == elems.length) {
        if (start > 0) {
          Array.copy(elems, start, elems, 0, length)
          limit -= start
          start = 0
        }
        else {
          val newelems = new Array[AnyRef](limit * 2)
          Array.copy(elems, 0, newelems, 0, limit)
          elems = newelems
        }
      }
      elems(limit) = elem.asInstanceOf[AnyRef]
      limit += 1
      this
    }
    def trimStart(n: Int): Unit = start += (n max 0)
    override def toString = s"ArrayBuffer(${elems.slice(start, limit).mkString(", ")})"
  }

  object ArrayBuffer extends IterableFactory[ArrayBuffer] {
    def fromIterator[B](it: Iterator[B]): ArrayBuffer[B] = it match {
      case Iterator.Concat(fst: ArrayBufferIterator[_], snd: ArrayBufferIterator[_]) =>
        val elems = new Array[AnyRef](fst.remaining + snd.remaining)
        Array.copy(fst.elems, fst.start, elems, 0, fst.remaining)
        Array.copy(snd.elems, snd.start, elems, fst.remaining, snd.remaining)
        new ArrayBuffer(elems, elems.length)
      case it @ Iterator.Partition(underlying, _, buf, _) =>
        while (underlying.hasNext) it.distribute()
        buf.asInstanceOf[ArrayBuffer[B]]
      case it if it.remaining >= 0 =>
        val elems = new Array[AnyRef](it.remaining)
        for (i <- 0 until elems.length) elems(i) = it.next.asInstanceOf[AnyRef]
        new ArrayBuffer[B](elems, elems.length)
      case _ =>
        val buf = new ArrayBuffer[B]
        while (it.hasNext) buf += it.next
        buf
    }
  }

  class ArrayBufferIterator[A](val elems: Array[AnyRef], initStart: Int, length: Int) extends RandomAccessIterator[A] {
    val limit = length
    def apply(n: Int) = elems(initStart + n).asInstanceOf[A]
  }

  /** Concrete collection type: View */
  class View[+A](it: => Iterator[A]) extends CanIterate[A] {
    def iterator = it
  }

  implicit class ViewOps[A](val v: View[A]) extends AnyVal with Ops[A] {
    def iterator = v.iterator
    def cache = to(ArrayBuffer).view
  }

  implicit class ViewMonoTransforms[A](val v: View[A])
  extends AnyVal with MonoTransforms[A, View[A]] {
    protected def iter = v.iterator
    protected def fromIter(it: => Iterator[A]): View[A] = new View(it)
  }

  implicit class ViewPolyTransforms[A](val v: View[A])
  extends AnyVal with PolyTransforms[A, View] {
    protected def iter = v.iterator
    protected def fromIter[B](it: => Iterator[B]) = new View(it)
  }

  /** Concrete collection type: String */
  implicit class StringOps(val s: String) extends AnyVal with Ops[Char] {
    def iterator: Iterator[Char] = new RandomAccessIterator[Char] {
      override val limit = s.length
      def apply(n: Int) = s.charAt(n)
    }
  }

  implicit class StringMonoTransforms(val s: String)
  extends AnyVal with MonoTransformsOfSeqs[Char, String] {
    protected def iter = StringOps(s).iterator
    protected def fromIter(it: => Iterator[Char]) = {
      val sb = new StringBuilder
      for (ch <- it) sb.append(ch)
      sb.toString
    }
  }

  implicit class StringPolyTransforms(val s: String)
  extends AnyVal with PolyTransforms[Char, Seq] {
    protected def iter = StringOps(s).iterator
    protected def fromIter[B](it: => Iterator[B]) = List.fromIterator(it)
    def map(f: Char => Char): String = {
      val sb = new StringBuilder
      for (ch <- s) sb.append(f(ch))
      sb.toString
    }
    def flatMap(f: Char => String) = {
      val sb = new StringBuilder
      for (ch <- s) sb.append(f(ch))
      sb.toString
    }
    def ++(xs: CanIterate[Char]): String = {
      val sb = new StringBuilder(s)
      for (ch <- xs.iterator) sb.append(ch)
      sb.toString
    }
    def ++(xs: String): String = s + xs
  }

/* ---------- Iterators --------------------------------------------------- */

  /** A core Iterator class */
  trait Iterator[+A] extends CanIterate[A] { self =>
    def hasNext: Boolean
    def next: A
    def iterator = this
    def foldLeft[B](z: B)(op: (B, A) => B): B =
      if (hasNext) foldLeft(op(z, next))(op) else z
    def foldRight[B](z: B)(op: (A, B) => B): B =
      if (hasNext) op(next, foldRight(z)(op)) else z
    def foreach(f: A => Unit): Unit =
      while (hasNext) f(next)
    def indexWhere(p: A => Boolean): Int = {
      var i = 0
      while (hasNext) {
        if (p(next)) return i
        i += 1
      }
      -1
    }
    def map[B](f: A => B): Iterator[B] = Iterator.Map(this, f)
    def flatMap[B](f: A => CanIterate[B]): Iterator[B] = Iterator.FlatMap(this, f)
    def ++[B >: A](xs: CanIterate[B]): Iterator[B] = Iterator.Concat(this, xs.iterator)
    def partition(p: A => Boolean): (Iterator[A], Iterator[A]) = {
      val lookaheadTrue, lookaheadFalse = new ArrayBuffer[A]
      (Iterator.Partition(this, p, lookaheadTrue, lookaheadFalse),
       Iterator.Partition[A](this, !p(_), lookaheadFalse, lookaheadTrue))
    }
    def drop(n: Int): Iterator[A] = Iterator.Drop(this, n)
    def zip[B](that: CanIterate[B]): Iterator[(A, B)] = Iterator.Zip(this, that.iterator)
    def reverse: Iterator[A] = {
      var elems: List[A] = Nil
      while (hasNext) elems = Cons(next, elems)
      elems.iterator
    }

    /** If this iterator results from applying a transfomation to another iterator,
     *  that other iterator, otherwise the iterator itself.
     */
    def underlying: Iterator[_] = this

    /** If the number of elements still to be returned by this iterator is known,
     *  that number, otherwise -1.
     */
    def remaining = -1
  }

  object Iterator {
    val empty: Iterator[Nothing] = new Iterator[Nothing] {
      def hasNext = false
      def next = ???
      override def remaining = 0
    }
    def apply[A](xs: A*): Iterator[A] = new RandomAccessIterator[A] {
      override val limit = xs.length
      def apply(n: Int) = xs(n)
    }
    def nextOnEmpty = throw new NoSuchElementException("next on empty iterator")

    case class Map[A, B](override val underlying: Iterator[A], f: A => B) extends Iterator[B] {
      def hasNext = underlying.hasNext
      def next = f(underlying.next)
      override def remaining = underlying.remaining
    }
    case class FlatMap[A, B](override val underlying: Iterator[A], f: A => CanIterate[B]) extends Iterator[B] {
      private var myCurrent: Iterator[B] = Iterator.empty
      private def current = {
        while (!myCurrent.hasNext && underlying.hasNext)
          myCurrent = f(underlying.next).iterator
        myCurrent
      }
      def hasNext = current.hasNext
      def next = current.next
    }
    case class Concat[A](override val underlying: Iterator[A], other: Iterator[A]) extends Iterator[A] {
      private var myCurrent = underlying
      private def current = {
        if (!myCurrent.hasNext && myCurrent.eq(underlying)) myCurrent = other
        myCurrent
      }
      def hasNext = current.hasNext
      def next = current.next
      override def remaining =
        if (underlying.remaining >= 0 && other.remaining >= 0)
          underlying.remaining + other.remaining
        else -1
    }
    case class Partition[A](override val underlying: Iterator[A], p: A => Boolean, lookahead: ArrayBuffer[A], dual: ArrayBuffer[A]) extends Iterator[A] {
      def distribute() = {
        val elem = underlying.next
        (if (p(elem)) lookahead else dual) += elem
      }
      final def hasNext: Boolean =
        !lookahead.isEmpty || underlying.hasNext && { distribute(); hasNext }
      final def next =
        if (hasNext) {
          val r = lookahead.head
          lookahead.trimStart(1)
          r
        } else Iterator.nextOnEmpty
    }
    case class Drop[A](override val underlying: Iterator[A], n: Int) extends Iterator[A] {
      var toSkip = n
      def hasNext: Boolean = underlying.hasNext && (
        toSkip == 0 || { underlying.next; toSkip -= 1; hasNext })
      def next = if (hasNext) underlying.next else nextOnEmpty
      override def remaining = (underlying.remaining - toSkip) max -1
    }
    case class Zip[A, B](override val underlying: Iterator[A], other: Iterator[B]) extends Iterator[(A, B)] {
      def hasNext = underlying.hasNext && other.hasNext
      def next = (underlying.next, other.next)
      override def remaining = underlying.remaining min other.remaining
    }
    case class Reverse[A](override val underlying: RandomAccessIterator[A]) extends RandomAccessIterator[A] {
      def apply(n: Int) = underlying.apply(underlying.limit - 1 - n)
      def limit = underlying.remaining
    }
  }

  trait RandomAccessIterator[+A] extends Iterator[A] { self =>
    def apply(n: Int): A
    def limit: Int
    var start = 0
    override def remaining = (limit - start) max 0
    def hasNext = start < limit
    def next: A = { val r = this(start); start += 1; r }
    override def drop(n: Int): Iterator[A] = { start += (n max 0); this }
    override def reverse: Iterator[A] = new Iterator.Reverse(this)
  }
}